Typescript `in` 运算符类型保护仅作为文字缩小

问题描述 投票:0回答:2

使用

in
运算符进行类型缩小是否仅适用于文字,还是我遗漏了某些内容? 请帮助我理解为什么会发生这种情况。

interface A {
    a: string;
}

interface B {
    b: number;
}

// This narrows the type correctly to A
function test(arg: A | B): string {
    if ('a' in arg) {
        return arg.a;
    }
    return arg.b.toFixed(2);
}

// This doesn't
function test2(arg: A | B): string {
    let a = 'a';
    if (a in arg) {
        return arg.a;
    }
    return arg.b.toFixed(2);
}

typescript typing typeguards
2个回答
3
投票

关于文档

对于 n in x 表达式,其中 n 是字符串文字或字符串文字类型,x 是联合类型,“true”分支缩小到具有可选或必需属性 n 的类型,“false”分支缩小到具有可选或必需属性 n 的类型具有可选或缺失的属性 n。

所以,我愿意打赌它只适用于文字

解决方法

interface A {
    a: string;
}

interface B {
    b: number;
}

// This narrows the type correctly to A
function test(arg: A | B): string {
    if ('a' in arg) {
        return arg.a;
    }
    return arg.b.toFixed(2);
}

const isIn = <T, Prop extends string>(obj: T, prop: Prop): obj is T & Record<Prop, unknown> => prop in obj
const isIn2 = <T, Prop extends string>(obj: T, prop: Prop): obj is T & Record<Prop, unknown> =>
    Object.prototype.hasOwnProperty.call(obj, prop)

// This doesn't
function test2(arg: A | B): string {
    const a: 'a' = 'a' as 'a';
    if (isIn(arg, a) /** OR isIn2(arg, a) */) {
        return arg.a; // A        
    }


    return arg.b.toFixed(2);
}


0
投票

是的,我同意这很奇怪。我有以下代码:

let name = ''

if (characteristic.uuid in peripheralsValueUuidNameMap) {
  const uuid =
    characteristic.uuid as keyof typeof peripheralsValueUuidNameMap

  name = peripheralsValueUuidNameMap[uuid]
}

我会假设 ts 推断出

as keyof typeof peripheralsValueUuidNameMap
但如果我以这种方式强制它,它只会停止抱怨。

我知道

characteristic.uuid
peripheralsValueUuidNameMap
的键,因为
in
检查成功。

peripheralsValueUuidNameMap
是一个 const 类型,所以关于它的一切都是已知的。 问题是,所有键都是
const
字符串,因此无法按字符串类型进行索引。奇怪的是,即使
in
检查已经完成了。

在这种情况下它确实有效:

if (characteristic.uuid in servCharMap) {
  const charData = servCharMap[characteristic.uuid]
}

因为 servCharMap 有类型

type ServCharMap = {
  [key: string]: ServChar
}

但这里我们甚至不需要

in
检查,
const charData = servCharMap[characteristic.uuid]
单独这段代码不会给出类型错误,因为我们正在使用字符串类型索引
servCharMap

所以综上所述,两种情况都有缺陷,都隐藏了枪。

© www.soinside.com 2019 - 2024. All rights reserved.