重命名对象/接口类型安全的键 [英] Rename keys of an object/interface typesafe

查看:20
本文介绍了重命名对象/接口类型安全的键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用映射函数动态重命名键.为此,我做了这个:

I want to dynamically rename keys with a mapping function. For this, I've made this:

interface DateRange {
    startDate: string;
    endDate: string;
}

function format<K extends string>(range: DateRange, mapping: {[X in keyof DateRange]: K}): {[P in K]: string} {
    return {
        [mapping.startDate]: range.startDate,
        [mapping.endDate]: range.endDate,
    };
}

当我用 as {[P in K]: string} 转换这个函数的返回值时,一切正常,但没有转换,它不会编译.

When I cast the return value of this function with as {[P in K]: string} it all works fine, but without the cast it doesn't compile.

错误信息:

TS2322: Type '{ [x: string]: string; }' is not assignable to type '{ [P in K]: string; }'.

从我看到的 DateRange 接口的两个键都使用了,所以返回值的键应该都是 K 类型.

From what I see both keys of the DateRange interface are used, so the keys of the return value should all be of type K.

函数应该是什么样子的,不需要强制转换?

How must the function look like, that a cast is not needed?

示例调用:

const formatted = format(
    {startDate: 'startDateValue', endDate: 'endDateValue'}, 
    {startDate: 'start', endDate: 'end'}
);
// formatted = {end: 'endDateValue', start: 'startDateValue'}

推荐答案

我可以重现你的问题,而且好像已经之前在 GitHub 问题中提到.该问题已被标记为已修复",但这部分显然没有.无论如何,这可能只是一个设计限制...... TypeScript 可以将具有泛型类型参数的对象表示为键的唯一方法是使用 映射类型,我怀疑 TypeScript 中的任何内容都会自动将对象文字解释为映射类型.不知道 GitHub 有没有更合适的现有 issue 或者是否有人应该打开一个.

I can reproduce your problem, and it seems to have been noted before in a GitHub issue. That issue has been marked "fixed", but this part of it obviously has not. Anyway, this might just be a design limitation... the only way TypeScript could represent an object with a generic type parameter as a key is with a mapped type, and I doubt that anything in TypeScript will interpret an object literal as a mapped type automatically. I don't know if there's a more appropriate existing issue in GitHub or if someone should open one.

现在,您必须处理变通方法.如果您小心的话,您使用的那个很好(断言返回值的类型).一个稍微类型安全的方法是一个一个地添加属性,如:

For now, you have to deal with workarounds. The one you used is fine (assert the type of the return value), if you're careful. A slightly more type-safe one is to add properties one by one, as in:

function format<K extends string>(
  range: DateRange, 
  mapping: { [X in keyof DateRange]: K }
): { [P in K]: string } {
  const ret = {} as { [P in K]: string }; // assertion
  ret[mapping.startDate] = range.startDate; // safer
  ret[mapping.endDate] = range.endDate; // safer
  return ret;
}

如果你遗漏了一个属性,它仍然不会抱怨,但它会阻止你添加其他随机的字符串值计算属性:

It still won't complain if you leave out a property, but it will stop you from adding random other string-valued computed properties:

  const badProp: string = "uh oh"
  return {
    [mapping.startDate]: range.startDate,
    [mapping.endDate]: range.endDate,
    [badProp]: "whoops" // no error
  } as { [P in K]: string };

对比

  const badProp: string = "uh oh"
  const ret = {} as { [P in K]: string };
  ret[mapping.startDate] = range.startDate;
  ret[mapping.endDate] = range.endDate;
  ret[badProp] = "whoops"; // error (implicit any)

不过,这对您来说可能不值得,而且您的类型断言是合理的.希望这有帮助.祝你好运!

That might not be worth it to you, though, and your type assertion is reasonable. Hope that's helpful. Good luck!

这篇关于重命名对象/接口类型安全的键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆