使用一般类型

时间:2019-04-23 03:47:45

标签: typescript

首先,我有一个类型定义,可以使用keyof

将所有属性映射为数字
type Numeric<T> = {
    [K in keyof T]: number
}

下面是我要使用的课程。

class Entity {
    aNumber: number;
}

下面是一个接受通用类型参数和类型为Numberic<T>的局部变量的函数。但是当我分配{ aNumber: 1 }时,出现了编译错误。

const fn = <T extends Entity>() => {
    const n: Numeric<T> = {
//        ^
//        Type '{ aNumber: number; }' is not 
//        assignable to type 'Numeric<T>'
        aNumber: 1
    };
};

我不知道为什么无法将{ aNumber: number; }分配给Numeric<T>,因为类型实参T必须从Entity扩展并且它必须包含一个名为{{ 1}}。这意味着aNumber必须是T类型的密钥,并且应该能够分配给aNumber

2 个答案:

答案 0 :(得分:3)

该错误消息具有误导性。但是,有一个错误,这就是TypeScript正在捕获的错误。确实,Entity没什么问题:

type Numeric<T> = {
    [K in keyof T]: number
}
interface Entity {
    aNumber: number
}

// No error
const n: Numeric<Entity> = {
    aNumber: 1
};

但是,当您说T extends Entity时,它会打开非数字值,例如

type Numeric<T> = {
    [K in keyof T]: number
}
interface Entity {
    aNumber: number
}

// No error
const n: Numeric<Entity> = {
    aNumber: 1
};

interface X extends Entity {
    notANumber: string
}
// Error. Thank you TypeScript
const o: Numeric<X> = {
    aNumber: 1
};

T extends Entity中使用Numeric时发生错误。

答案 1 :(得分:1)

<T extends Entity>施加的约束应被视为T应该满足的最低要求。这表示“ T至少应包含aNumber: number对”。

让我们看看const n: T。这意味着“ n至少应包含T中的任何键值对”。

现在我们知道,T有一对aNumber: number,但请记住,这只是最低要求。 T也可能是{ aNumber: number; aString: string }。因此,这也会给您带来错误。

// if you understand this:
const n: { aNumber: number; aString: string } = { aNumber: 42 }  // error, of course
// you see why this is an error:
const n: T = { aNumber: 42 }  // also error

您永远无法说出T的确切含义。 keyof T很好,我们肯定至少知道T的钥匙之一。

const k: keyof T = "aNumber"

为证明我的观点,让我们回顾一个非通用案例。以@basarat的代码为例,这里的X不是流派的。

type Numeric<T> = {
    [K in keyof T]: number
}

type OptionalNumeric<T> = {
    [K in keyof T]?: number
}

interface Entity {
    aNumber: number
}

interface X extends Entity {
    notANumber: string
}

// Error, because `notANumber` is missing
const o: Numeric<X> = { aNumber: 1 };
// Correct
const o1: Numeric<X> = { aNumber: 1, notANumber: 2 };
// Also correct, because all keys are optional.
const o2: OptionalNumeric<X> = { aNumber: 1 };

旁注。以上应解释您的情况。但是,我确实相信TS中存在错误。

我认为,如果您在原始情况下使用OptionalNumeric,那么您想要的应该可以工作。但是事实并非如此。涉及泛型类型参数时应该是一个缺陷。