为什么会出现这个错误?
这里有一个例子:
class StringClass {
val: string;
constructor(val: string) {
this.val = val;
}
}
class NumberClass {
val: number
constructor(val: number) {
this.val = val;
}
}
type Check<A> = A extends string ? typeof StringClass : typeof NumberClass
class test<A extends string | number, B extends Check<A>> {
val: B;
constructor(val: A, Class: B) {
// Type 'string' is not assignable to type 'never'
this.val = new Class(val);
}
}
const result = new test('2', StringClass)
在上述情况下,val 推断为never,因为
同一类型变量在逆变位置的多个候选导致推断出交集类型。
因此string & number === never
考虑这个例子:
class StringClass {
val: { string: string };
constructor(val: { string: string }) {
this.val = val;
}
}
class NumberClass {
val: { number: number }
constructor(val: { number: number }) {
this.val = val;
}
}
type Check<A> = A extends string ? typeof StringClass : typeof NumberClass
class test<A extends string|number, B extends Check<A>> {
val: B;
constructor(val: A, Class: B) {
// Type 'string' is not assignable to type '{ string: string; } & { number: number; }'
this.val = new Class(val);
}
}
const result = new test('2', StringClass)
val 是{ string: string; } & { number: number; }。
那么,如何解决呢?
您可以摆脱泛型并通过适当的限制重载您的构造函数
class StringClass {
val: string;
constructor(val: string) {
this.val = val;
}
}
class NumberClass {
val: number
constructor(val: number) {
this.val = val;
}
}
type Check<A> = A extends string ? typeof StringClass : typeof NumberClass
interface Overloading {
new(val: string): any
new(val: number): any
new(val: string | number): any
}
class test {
val: StringClass | NumberClass
constructor(val: number, Class: typeof NumberClass)
constructor(val: string, Class: typeof StringClass)
constructor(val: never, Class: typeof StringClass & typeof NumberClass) {
this.val = new Class(val)
}
}
const _ = new test('2', StringClass) // ok
const __ = new test(2, StringClass) // expected error
Playground
通常,运行时值不能依赖于一般条件(请参阅Check)。不安全。
这就是这里的原因:
class StringClass {
val: string;
constructor(val: string) {
this.val = val;
}
}
class NumberClass {
val: number
constructor(val: number) {
this.val = val;
}
}
class test<A, B extends {
0: typeof StringClass,
1: typeof NumberClass,
2: never
}[A extends string ? 0 : A extends number ? 1 : 2]> {
val: B
constructor(val: A, Class: B) {
this.val = new Class(val) // error
}
}
你有一个错误。
在这种情况下,你总是可以使用类型断言as never:
class StringClass {
val: string;
constructor(val: string) {
this.val = val;
}
}
class NumberClass {
val: number
constructor(val: number) {
this.val = val;
}
}
class test<A, B extends {
0: typeof StringClass,
1: typeof NumberClass,
2: never
}[A extends string ? 0 : A extends number ? 1 : 2]> {
val: StringClass | NumberClass
constructor(val: A, Class: B) {
this.val = new Class(val as never) // type asserion
}
}
const _ = new test('2', StringClass) // ok
const __ = new test(2, StringClass) // expected error
在这里使用类型断言是否安全?我不确定。我认为这取决于你。如果此代码仅用于测试 - 就像我一样使用 as never 或 never。
如果这是生产代码 - 请使用条件语句