打字稿以类型安全获取对象的键名

时间:2021-04-25 23:34:00

标签: typescript

如何从类型安全的对象或记录中获取密钥?
下面的示例打印 dog maxdog 是硬编码字符串。我可以以某种方式删除硬编码吗?

type pettype = 'dog' | 'cat'

const pets: Record<pettype, string> = {
  'dog': 'max',
  'cat': 'juliet',
}

// Print "dog max" without hardcoding 'dog'
console.log('dog', pets.dog)
// Looking at something like nameof(pets.dog)

3 个答案:

答案 0 :(得分:0)

而不是执行与 nameof(pets.dog) 相同的 nameof('max') 将 pettype 作为 nameof 的参数

const nameof(pet: pettype) => {
  console.log(pet, pets[pet])
}

如果您确实想通过名称查找宠物的类型,则应该切换宠物的键和值。

答案 1 :(得分:0)

如果您不想在后面的代码中使用字符串字面量“dog”并且想使用诸如常量字符串变量之类的东西,您可以定义 const 变量。

例如

const DOG = "dog";
const CAT = "cat";

type pettype = typeof DOG | typeof CAT;

const pets: Record<pettype, string> = {
  [DOG]: 'max',
  [CAT]: 'juliet',
};

console.log(DOG, pets[DOG])

注意typeof运算符在定义联合类型时使用,括号在变量作为键时使用。

答案 2 :(得分:0)

我不能 100% 确定这是否是您想要的,但根据您的示例,我假设您只想通过不带 "dog max" 字符串的对象来打印 "dog"

type PetType = 'dog' | 'cat';

const pets: Record<PetType, string> = {
  'dog': 'max',
  'cat': 'juliet',
}

function nameof(name: string) {
  // find key by value
  const [petType] = Object.entries(pets).find(([_petType, petName]) => petName === name) || []
  console.log(petType, name);
}

nameof(pets.dog); // dog max
nameof(pets.cat); // cat juliet
nameof("foo"); // undefined foo

但是,如果有同名的宠物,这可能会成为一个问题

TS Playground


或者更严格,如果宠物名称是定义的/静态值:

// Generic type to get object value as union type
type ValueOf<T> = T[keyof T];

type PetType = 'dog' | 'cat';
type PetName = 'max' | 'juliet';

const pets: Record<PetType, PetName> = {
  'dog': 'max',
  'cat': 'juliet',
}

function nameof(name: ValueOf<typeof pets>) {
  const [petType] = Object.entries(pets).find(([_petType, petName]) => petName === name) || []
  console.log(petType, name);
}

nameof(pets.dog); // dog max
nameof(pets.cat); // cat juliet
nameof("foo"); // "foo" is not assignable to parameter of type ValueOf<Record<PetType, PetName>>

TS Playground

或更干净的版本:

// Generic type to get object value as union type
type ValueOf<T> = T[keyof T];

const pets = {
  dog: 'max',
  cat: 'juliet',
} as const;

// You can also extract the type if needed
type PetKeys = keyof typeof pets; // "dog" | "cat"
type PetNames = ValueOf<typeof pets>; // "max" | "juliet"

function nameof(name: ValueOf<typeof pets> /* or PetNames */) {
  const [petType] = Object.entries(pets).find(([_petType, petName]) => petName === name) || []
  console.log(petType, name);
}

nameof(pets.dog); // dog max
nameof(pets.cat); // cat juliet
nameof("foo"); // Error because "foo" != "max" or "juliet"

TS Playground