打字稿条件类型缺少属性
Typescript conditional type missing properties
我无法理解为什么下面的 TypeScript 代码会失败,而看似一切正常:
interface Base { basic: boolean };
interface Super { basic: boolean; extra: boolean };
type Options<T> = T extends Super ? { isSuper: boolean } : { notSuper: boolean }
const baseOptions: Options<{ basic: boolean }> = { notSuper: true }; // ok
const superOptions: Options<{ basic: boolean; extra: boolean }> = { isSuper: true }; // ok
type MakeOptions = <T>() => Options<T>
function withOptions <T>(makeOptions: MakeOptions): void {
const options = makeOptions<T>();
console.log(options.notSuper); // Error: Property 'notSuper' does not exist on type 'Options<T>'.(2339)
console.log(options.isSuper); // Error: Property 'isSuper' does not exist on type 'Options<T>'.(2339)
}
我希望 options.isSuper
为 undefined | { isSuper: boolean }
,options.notSuper
为 undefined | { notSuper: boolean }
相反,Typescript 将这些属性全部删除。
改成
问题解决
type Options<T> = T extends Super ? { isSuper: boolean; notSuper?: undefined } : { notSuper: boolean; isSuper?: undefined }
不过好像没必要。
在 Options<T>
中,如你所愿 return 一个带有参数 isSuper
或 notSuper
的对象,我为它们添加了一个接口。
interface IisSuper { isSuper: boolean }
interface InotSuper { notSuper: boolean }
在 Options<T>
中,因为它可以是上述接口之一,所以我为它创建了一个名为 TSuper
的联合类型。
type Options<T> = T extends Super ? IisSuper : InotSuper
type TSuper = IisSuper | InotSuper
在函数 withOptions<T>
中,我使用了 as
关键字,这是一个类型断言,它告诉编译器将该对象视为另一种类型,而不是编译器推断该对象的类型。在这种情况下,它是 IisSuper
和 InotSuper
的并集,Options<T>
可以作为
存在。
由于 Typescript 无法在运行时保证 options
的类型,因为您想要访问 notSuper
或 isSuper
因此您必须使用 [=27= 缩小范围] options
的关键字以访问所需类型的参数。
function withOptions <T>(makeOptions: MakeOptions): void {
const options = makeOptions<T>() as TSuper;
if('notSuper' in options){
console.log(options.notSuper);
}
else if('isSuper' in options){
console.log(options.isSuper);
}
}
最终代码:
interface Base { basic: boolean };
interface Super { basic: boolean; extra: boolean };
interface IisSuper { isSuper: boolean }
interface InotSuper { notSuper: boolean }
type Options<T> = T extends Super ? IisSuper : InotSuper
type MakeOptions = <T>() => Options<T>
type TSuper = IisSuper | InotSuper
const baseOptions: Options<{ basic: boolean }> = { notSuper: true };
const superOptions: Options<{ basic: boolean; extra: boolean }> = { isSuper: true };
function withOptions <T>(makeOptions: MakeOptions): void {
const options = makeOptions<T>() as TSuper;
if('notSuper' in options){
console.log(options.notSuper);
}
else if('isSuper' in options){
console.log(options.isSuper);
}
}
我无法理解为什么下面的 TypeScript 代码会失败,而看似一切正常:
interface Base { basic: boolean };
interface Super { basic: boolean; extra: boolean };
type Options<T> = T extends Super ? { isSuper: boolean } : { notSuper: boolean }
const baseOptions: Options<{ basic: boolean }> = { notSuper: true }; // ok
const superOptions: Options<{ basic: boolean; extra: boolean }> = { isSuper: true }; // ok
type MakeOptions = <T>() => Options<T>
function withOptions <T>(makeOptions: MakeOptions): void {
const options = makeOptions<T>();
console.log(options.notSuper); // Error: Property 'notSuper' does not exist on type 'Options<T>'.(2339)
console.log(options.isSuper); // Error: Property 'isSuper' does not exist on type 'Options<T>'.(2339)
}
我希望 options.isSuper
为 undefined | { isSuper: boolean }
,options.notSuper
为 undefined | { notSuper: boolean }
相反,Typescript 将这些属性全部删除。
改成
问题解决type Options<T> = T extends Super ? { isSuper: boolean; notSuper?: undefined } : { notSuper: boolean; isSuper?: undefined }
不过好像没必要。
在 Options<T>
中,如你所愿 return 一个带有参数 isSuper
或 notSuper
的对象,我为它们添加了一个接口。
interface IisSuper { isSuper: boolean }
interface InotSuper { notSuper: boolean }
在 Options<T>
中,因为它可以是上述接口之一,所以我为它创建了一个名为 TSuper
的联合类型。
type Options<T> = T extends Super ? IisSuper : InotSuper
type TSuper = IisSuper | InotSuper
在函数 withOptions<T>
中,我使用了 as
关键字,这是一个类型断言,它告诉编译器将该对象视为另一种类型,而不是编译器推断该对象的类型。在这种情况下,它是 IisSuper
和 InotSuper
的并集,Options<T>
可以作为
由于 Typescript 无法在运行时保证 options
的类型,因为您想要访问 notSuper
或 isSuper
因此您必须使用 [=27= 缩小范围] options
的关键字以访问所需类型的参数。
function withOptions <T>(makeOptions: MakeOptions): void {
const options = makeOptions<T>() as TSuper;
if('notSuper' in options){
console.log(options.notSuper);
}
else if('isSuper' in options){
console.log(options.isSuper);
}
}
最终代码:
interface Base { basic: boolean };
interface Super { basic: boolean; extra: boolean };
interface IisSuper { isSuper: boolean }
interface InotSuper { notSuper: boolean }
type Options<T> = T extends Super ? IisSuper : InotSuper
type MakeOptions = <T>() => Options<T>
type TSuper = IisSuper | InotSuper
const baseOptions: Options<{ basic: boolean }> = { notSuper: true };
const superOptions: Options<{ basic: boolean; extra: boolean }> = { isSuper: true };
function withOptions <T>(makeOptions: MakeOptions): void {
const options = makeOptions<T>() as TSuper;
if('notSuper' in options){
console.log(options.notSuper);
}
else if('isSuper' in options){
console.log(options.isSuper);
}
}