我试图弄清楚为什么打字稿不喜欢下面的结构。编译器错误在代码的注释中。
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
是否应该缩小类型的范围?
答案 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不允许接口将符号用作键。
一些其他想法
我不知道您在此处使用泛型的原因,但是如果您知道将向该函数传递一个对象,并且您对该函数的结构有所了解,那么也可以只使用一个接口>