首页 > 解决方案 > 使用 keyof 查找的 Typescript 界面模板

问题描述

我想要类似的东西


interface Operation<T, K extends keyof T> {
  key: keyof T;
  operation: 'add' | 'remove';
  value: T[K];
}

但不需要K作为模板传递;基本上,我希望能够做到:

interface User {
  name: string;
  age: number;
}

// this is valid
const operation: Operation<User> = {
  key: 'name',
  operation: 'add',
  value: 'the value',
}
// this is valid
const operation: Operation<User> = {
  key: 'age',
  operation: 'add',
  value: 123,
}

// this is not valid
const operation: Operation<User> = {
  key: 'age',
  operation: 'add',
  value: '123',  // type is wrong, should be number
}

我该怎么做呢?

标签: javascripttypescript

解决方案


如果我们通过使用函数来改进创建对象的方式,就个人而言,我们可以。这个想法如下:

首先,创建类型获取任何属性的值类型:

type ValueType<T, K> = K extends keyof T ? T[K] : never;

然后定义Operation类型:

type Operation<T, K> = {
  key: K
  operation: 'add' | 'delete'
  value: ValueType<T, K>
}

现在关键是在这里定义构建函数而不是直接创建对象,因为我们热衷于阅读参数:

type BuildOperation<T> = <K>(arg: K) => (arg: Operation<T, K>) => Operation<T, K>


function build<T>(): BuildOperation<T> {
  return (key) => (props) => ({
    key,
    ...props,
  });  
}

最后,我们可以通过设置 keyas const来使用我们的函数来确保 Typescript 不会推断为字符串:

type User = { name: string; age: number }

const obj = build<User>()('age' as const)({
  key: 'age',
  value: 20, // It will hint you this is number
  operation: 'add',
});

推荐阅读