打字稿避免使用泛型导出类型

时间:2021-03-13 22:56:13

标签: typescript typescript-generics

我正在学习 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 的类型;

是否有更好的方法使用泛型来推断类型,或者是否有必要导出类型规范?

1 个答案:

答案 0 :(得分:3)

出现问题是因为 Typescript 为您的 printSpec 变量分配了一个类型,该变量使用 string 来描述值 "age""lastName"string 过于宽泛,因为我们不再知道这些值是 User 接口的有效键。

解决方案 #1:没有中间变量

如果您避免使用中间变量 printSpec,您将不会有任何错误,因为不会发生类型扩展。您可以将您的规范直接传递给 objectPrinter 函数:

objectPrinter(user, [
  { key: "age", label: "Trips Around Sun" },
  { key: "lastName" },
]);

解决方案 #2: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);

解决方案 #3:分配 Spec 类型

<块引用>

为了解决这个问题,我还可以导出 interface Spec 并指定 printSpec 的类型

你的建议肯定会奏效。您显然已经知道这一点,但为了完整起见,我将其包括在此处。

const printSpec: Spec<User>[] = [
  { key: "age", label: "Trips Around Sun" },
  { key: "lastName" },
];

objectPrinter(user, printSpec);