一段时间后,我再次使用TypeScript,但是我一直陷在这个问题上。
export class CrossBrowserStorage<T> {
getValue<P extends keyof T>(
key: P,
defaultValue: T[P]
): Observable<T[P]> {
return this.getValues({ [key]: defaultValue }).pipe(map(values => values[key]));
----^ TS2345: Argument of type '{ [x: string]: T[P]; }' is not assignable
to parameter of type 'Partial '
}
getValues(keys: Partial<T>): Observable<Partial<T>> {
return from(browser.storage.sync.get(keys) as Promise<Partial<T>>);
}
}
TS2345:类型的
'{ [x: string]: T[P]; }'
参数无法分配给类型的参数'Partial'
无法理解如何解决此问题,同时保持正确的输入。
不幸的是,编译器无法为您验证这一点,在这种情况下,您对编译器了解更多,一种合理的解决方案是使用类型断言:
class Class<T> {
f<K extends keyof T>(k: K, v: T[K]) {
const badPartial: Partial<T> = { [k]: v }; // error!
const goodPartial: Partial<T> = { [k]: v } as Pick<T, K> & Partial<T>; // okay
}
}
这就是您需要做的。但是为什么会这样呢?编译器似乎面临两个主要绊脚石。
第一个绊脚石是,如果键是单个静态已知的文字或唯一符号类型,则编译器仅知道如何解释计算的属性:
const k1 = "a";
const o1 = { [k1]: 123 };
// const o1: {[k1]: number};
o1.a; // okay
o1.b; // error
相反,如果键类型是泛型或字符串文字的并集,则编译器string
会将其扩展为并将结果对象视为带有字符串索引签名的对象,从而得出奇怪的结果:
const k2 = Math.random() < 0.5 ? "a" : "z";
const o2 = { [k2]: 123 };
// const o2: {[x: string]:number};
o2.a; // no error, but might not exist
o2.b; // no error, but *definitely* doesn't exist
function foo<K extends string>(k3: K) {
const o3 = { [k3]: 123 };
// const o3: {[x: string]:number};
o3.a; // no error, but probably doesn't exist
}
这是TypeScript中的未解决问题。请参阅microsoft / TypeScript#13948。很明显,对于字面量的并集来说,要做的“正确的事情”是什么?大概o2
上面应该是type {a: number} | {z: number}
。使用泛型还不清楚。也许o3
上面应该是类型Partial<Record<K, number>>
。无论如何,字符串索引签名都不是一件好事,它会破坏您所看到的东西。
另一个绊脚石是,即使编译器意识到计算出的属性可以根据泛型类型分配给某种合适的类型,T
并且K
也可能无法识别出该类型可以分配给Partial<T>
。对于人类来说,这很容易理解,但是编译器不一定会推理出这种类型的高阶类型操作。与此相关的规范性开放问题可能是microsoft / TypeScript#28884,其中的问题是,当或为通用时,Pick<T, K> & Omit<T, K>
它不被视为与兼容。对于任何静态已知的type和,编译器都可以进行分析:确实被视为可分配给T
T
K
T
K
Pick<{a: string, b: string}, "a"> & Omit<{a: string, b: string}, "a">
{a: string, b: string}
。但是一旦使类型成为通用类型,编译器就会基本放弃。
由于这两个原因,让编译器为您验证可分配性的可能性很小。我能提供的最佳建议是使用该类型声明并继续。
好吧,希望能有所帮助;祝好运!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句