keyof不允许使用参数(“预期0个参数,但有1个”)

时间:2018-10-09 14:41:56

标签: typescript

尝试以递归/嵌套的方式实现原始属性为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>的变量?

Playground link

1 个答案:

答案 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