尝试以递归/嵌套的方式实现原始属性为KnockoutObservable<Primitive>
类型的键入:
export type Primitive = string | number | boolean | undefined | null;
export type KnockoutMappedProperty<T> = T extends Primitive ? KnockoutObservable<T> : KnockoutMappedType<T>;
export type KnockoutMappedType<T> = {
[Property in keyof T]: KnockoutMappedProperty<T[Property]>;
};
interface KnockoutObservable<T> extends KnockoutSubscribable<T>, KnockoutObservableFunctions<T> {
(): T;
(value: T): void;
/*...*/
}
在不带参数的情况下调用函数会编译:
const v1: KnockoutMappedType<{ prop: boolean }> = null;
const propValue: boolean = v1.prop();
传递参数不会像在(value: T): void;
中不存在KnockoutObservable<T>
一样进行编译:
v1.prop(true); // Gives compiler error: Expected 0 arguments, but got 1
Intellisense告诉我v1.prop
的类型为KnockoutObservable<true> | KnockoutObservable<false>
。为什么将某些内容拆分为仅应为KnockoutObservable<boolean>
的并集类型?
以下再次编译正常:
const prop: KnockoutObservable<boolean> = v1.prop;
prop(true);
为什么需要引入类型为KnockoutObservable<boolean>
的变量?
答案 0 :(得分:2)
问题在于,条件类型如docs中所述在联合上分布。虽然起初并不明显,boolean
是一个联合,但联合true | false
。这意味着映射的prop1
将是KnockoutObservable<true> | KnockoutObservable<false>
类型。这意味着唯一可调用的签名将是通用签名,而没有任何参数。
要停止分发行为,可以将类型参数放在元组中(因为分发仅发生在裸类型参数上)
export type Primitive = string | number | boolean | undefined | null;
export type KnockoutMappedProperty<T> = [T] extends [Primitive] ? KnockoutObservable<T> : KnockoutMappedType<T>;
export type KnockoutMappedType<T> = {
[Property in keyof T]: KnockoutMappedProperty<T[Property]>;
};
interface KnockoutObservable<T> extends KnockoutSubscribable<T>, KnockoutObservableFunctions<T> {
(): T;
(value: T): void;
/*...*/
}
const v1: KnockoutMappedType<{ prop: boolean }> = null;
const propValue: boolean = v1.prop();
v1.prop(true); // ok