将类型缩小为具有某些属性的对象

时间:2020-09-03 09:14:15

标签: typescript

我试图弄清楚为什么打字稿不喜欢下面的结构。编译器错误在代码的注释中。

const BAR = Symbol();

function foo<T>(that: T) {
  if (that !== null && typeof that === "object" && BAR in that) {
    // Element implicitly has an 'any' type because expression of type 'unique symbol' can't be used to index type 'unknown'.
    // Property '[BAR]' does not exist on type 'unknown'.ts(7053)
    const bar = that[BAR];
    console.log(bar);
  }
}

function foo2<T>(that: T) {
  if (that !== null && typeof that === "object" && "BAR" in that) {
    // Element implicitly has an 'any' type because expression of type '"BAR"' can't be used to index type 'unknown'.
    // Property 'BAR' does not exist on type 'unknown'.ts(7053)
    const bar = that["BAR"];
    console.log(bar);
  }

if是否应该缩小类型的范围?

2 个答案:

答案 0 :(得分:1)

这个怎么样?不可能,这是最好的解决方案,但它确实有效... Playground

const BAR = Symbol();
function foo<T>(that: T) {
  if (that !== null && typeof that === "object" && hasProperty(that, BAR)) {
    const bar = that[BAR];
    console.log(bar);
  }
}

function foo2<T>(that: T) {
  if (that !== null && typeof that === "object" && hasProperty(that, "BAR")) {
    const bar = that["BAR"];
    console.log(bar);
  }
}

function hasProperty<P extends keyof any>(obj: any, prop: P): obj is { [_ in P]: unknown } {
    return prop in obj;
}

答案 1 :(得分:-1)

由于通用函数没有约束,因此TS不知道T将是什么。因此,它抱怨。 TS执行静态类型分析,而不执行运行时分析。您的if语句不属于前一类。

TypeScript的功能来自其显式性,因此,如果您已经知道要传递给函数(that)的属性具有确定的键(BAR),则应进行声明

如果您要坚持使用泛型,可以这样做,例如:

const BAR = 'BAR';

interface Barable {
  [BAR]: any,
}

function foo<T extends Barable>(that: T) {
  if (that !== null && typeof that === "object" && BAR in that) {
    const bar = that[BAR];
    console.log(bar);
  }
}

/*
string alternative:
 
interface Barable {
    BAR: any,
}

.. and then your string function from above

*/

请注意,TS不允许接口将符号用作键。


一些其他想法

我不知道您在此处使用泛型的原因,但是如果您知道将向该函数传递一个对象,并且您对该函数的结构有所了解,那么也可以只使用一个接口