typescript - 我可以在 TypeScript 中指定值类型,但仍让 TS 推断出键类型吗?

标签 typescript

如果我在 TypeScript 中创建这个常量:

const PARAMS = {
  green: {color: 0x007700},
  black: {color: 0x000000},
  white: {color: 0xffffff},
};

它将类型推导出为 { green: {color: number};黑色:{颜色:数字};白色:{颜色:数字}; }.

但我从上下文中知道值的类型应该是 THREE.MeshBasicMaterialParameters。我可以使用索引类型来声明它:

const PARAMS: {[name: string]: THREE.MeshBasicMaterialParameters} = {
  green: {color: 0x007700},
  black: {color: 0x000000},
  white: {color: 0xffffff},
};

但随后我失去了键的特定可能性(“绿色”、“黑色”或“白色”)。我可以通过写出我想要的完整类型来更精确地建模:

const PARAMS: {
  green: THREE.MeshBasicMaterialParameters,
  black: THREE.MeshBasicMaterialParameters,
  white: THREE.MeshBasicMaterialParameters
} = {
  green: {color: 0x007700},
  black: {color: 0x000000},
  white: {color: 0xffffff},
};

但这非常冗长且重复。

有没有办法以更简洁的方式获取我想要的类型?

最佳答案

您可以通过使用通用映射类型来减少冗长

type ParamsType<Colors extends string> = {
    [c in Colors]: THREE.MeshBasicMaterialParameters;
}

const PARAMS: ParamsType<'green' | 'black' | 'white'> = {
  green: {color: 0x007700},
  black: {color: 0x000000},
  white: {color: 0xffffff},
};

但是你仍然需要重复颜色名称两次。如果你想让 typescript 推导 key ,你必须引入中间函数,在运行时完全没有用处。我不知道还有什么其他方法可以让 typescript 推断通用参数 - there is a proposal on github允许扣除默认模板参数,但到目前为止尚未实现任何内容。

function inferColorKeys<Colors extends string>(params: ParamsType<Colors>): ParamsType<Colors> {
    return params;
}


const PARAMS = inferColorKeys({
  green: {color: 0x007700},
  black: {color: 0x000000},
  white: {color: 0xffffff},
});

更新

您可以按照 @jcalz 的建议,通过创建 inferKeys 使其完全通用。进入一个接受显式泛型参数并返回一个推断其泛型参数的函数的函数。它必须是两个函数,因为一个函数不能有一些显式的通用参数和一些推断的参数。此外,它还利用内置的 Record类型定义为 type Record<K extends string, V> = {[k in K]: V} .

const inferKeys = <V>() => <K extends string>(x: Record<K,V>): Record<K,V> => x;

const PARAMS = inferKeys<THREE.MeshBasicMaterialParameters>()({
    green: {color: 0x007700},
    black: {color: 0x000000},
    white: {color: 0xffffff},
});

PARAMS 的类型被推断为

Record<"green" | "black" | "white", THREE.MeshBasicMaterialParameters>

关于typescript - 我可以在 TypeScript 中指定值类型,但仍让 TS 推断出键类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46100834/

相关文章:

javascript - Typescript 组件中的“this”与 Angular2 中的 ES5

node.js - Visual Studio NodeJS 工具 - 如何打包项目?创建 NPM?

使用 LocalStorage 的 Angular 6 BehaviorSubject

javascript - 父组件如何将 HTML 传递给 Angular 中的子组件?

typescript - 如何在接口(interface)声明中使用 PromiseConstructorLike 实例的原型(prototype)?

javascript - e.preventDefault() 不适用于 MVC 中的提交按钮和 anchor 标记

typescript - 相当于 Typescript 的 Babel 插件?

javascript - Require.js 单例到 TypeScript

angular - 动态安装 Angular 2 指令

javascript - 将 “then.catch”嵌套在JavaScript的另一个 “then”中,可以期望什么结果?