我正在学习 Typescript,但我正在为泛型而苦苦挣扎。
我创建了一个简单的函数,可以按特定顺序打印给定对象的键/值。可以提供额外的标签属性来打印密钥字符串的替代项。
// object-printer.ts
interface Spec<T> {
key: keyof T;
label?: string;
}
export default function objectPrinter<T>(ob: T, printSpec: Spec<T>[]): void {
printSpec.forEach((spec) => {
let label = spec.label || spec.key;
console.log(`${label}: ${ob[spec.key]}`);
});
}
然后我导入函数并使用它
import objectPrinter from "./object-printer";
interface User {
firstName: string;
lastName: string;
age: number;
}
const user: User = {
firstName: "Wurzel",
lastName: "Gummage",
age: 100,
};
const printSpec = [
{ key: "age", label: "Trips Around Sun" },
{ key: "lastName" },
];
objectPrinter(user, printSpec); // Typescript complains about type of printSpec
// Trips Around Sun: 100
// lastName: Gummage
打字稿给我一个错误:
<块引用>'({ key: string; label: string; } | { key: string; 标签?:未定义; })[]' 不能分配给类型的参数 '规格[]'。输入 '{ 键:字符串;标签:字符串; } | { 钥匙: 细绳;标签?:未定义; }' 不可分配给类型 'Spec'。 输入 '{ 键:字符串;标签:字符串; }' 不可分配给类型 'Spec'。 属性“key”的类型不兼容。 类型 'string' 不能分配给类型 'keyof User'。
为了解决这个问题,我还可以导出 interface Spec
并指定 printSpec
的类型;
是否有更好的方法使用泛型来推断类型,或者是否有必要导出类型规范?
答案 0 :(得分:3)
出现问题是因为 Typescript 为您的 printSpec
变量分配了一个类型,该变量使用 string
来描述值 "age"
和 "lastName"
。 string
过于宽泛,因为我们不再知道这些值是 User
接口的有效键。
如果您避免使用中间变量 printSpec
,您将不会有任何错误,因为不会发生类型扩展。您可以将您的规范直接传递给 objectPrinter
函数:
objectPrinter(user, [
{ key: "age", label: "Trips Around Sun" },
{ key: "lastName" },
]);
as const
Typescript 有一个特殊的 as const
断言,使其将变量视为不可变常量并将所有字符串读取为它们的字面值。
如果我们声明整个 printSpec
变量 as const
,那么我们必须处理类型中的 readonly
问题。但是我们可以将 as const
添加到键字符串中。
const printSpec = [
{ key: "age" as const, label: "Trips Around Sun" },
{ key: "lastName" as const},
];
objectPrinter(user, printSpec);
Spec
类型为了解决这个问题,我还可以导出 interface Spec
并指定 printSpec
的类型
你的建议肯定会奏效。您显然已经知道这一点,但为了完整起见,我将其包括在此处。
const printSpec: Spec<User>[] = [
{ key: "age", label: "Trips Around Sun" },
{ key: "lastName" },
];
objectPrinter(user, printSpec);