首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有没有可能在TypeScript中精确地键入_.invert?

有没有可能在TypeScript中精确地键入_.invert?
EN

Stack Overflow用户
提问于 2019-06-02 22:10:48
回答 3查看 2.6K关注 0票数 6

在lodash中,_.invert函数反转对象的键和值:

代码语言:javascript
复制
var object = { 'a': 'x', 'b': 'y', 'c': 'z' };

_.invert(object);
// => { 'x': 'a', 'y': 'b', 'z': 'c' }

lodash类型currently声明总是返回一个stringstring→映射:

代码语言:javascript
复制
_.invert(object);  // type is _.Dictionary<string>

但有时,尤其是在使用const assertion的情况下,更精确的类型会更合适:

代码语言:javascript
复制
const o = {
  a: 'x',
  b: 'y',
} as const;  // type is { readonly a: "x"; readonly b: "y"; }
_.invert(o);  // type is _.Dictionary<string>
              // but would ideally be { readonly x: "a", readonly y: "b" }

有可能得到如此精确的类型吗?下面的声明很接近:

代码语言:javascript
复制
declare function invert<
  K extends string | number | symbol,
  V extends string | number | symbol,
>(obj: Record<K, V>): {[k in V]: K};

invert(o);  // type is { x: "a" | "b"; y: "a" | "b"; }

键是正确的,但是值是输入键的并集,即您失去了映射的特异性。有可能让这一切变得完美吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-06-02 22:59:44

您可以使用更复杂的映射类型来保留正确的值:

代码语言:javascript
复制
const o = {
    a: 'x',
    b: 'y',
} as const;

type AllValues<T extends Record<PropertyKey, PropertyKey>> = {
    [P in keyof T]: { key: P, value: T[P] }
}[keyof T]
type InvertResult<T extends Record<PropertyKey, PropertyKey>> = {
    [P in AllValues<T>['value']]: Extract<AllValues<T>, { value: P }>['key']
}
declare function invert<
    T extends Record<PropertyKey, PropertyKey>
>(obj: T): InvertResult<T>;

let s = invert(o);  // type is { x: "a"; y: "b"; }

AllValues首先创建一个包含所有keyvalue对的联合(因此对于您的示例,它将是{ key: "a"; value: "x"; } | { key: "b"; value: "y"; })。在映射的类型中,我们将映射到联合中的所有value类型,并且对于每个value,我们使用Extract提取原始key。只要没有重复的值,这就可以很好地工作(如果有重复的值,我们将在值出现的位置获得键的并集)

票数 22
EN

Stack Overflow用户

发布于 2019-08-30 20:32:54

Titian Cernicova-Dragomir的解决方案真的很酷。今天,我找到了另一个用条件类型交换对象键和值的方法:

代码语言:javascript
复制
type KeyFromValue<V, T extends Record<PropertyKey, PropertyKey>> = {
  [K in keyof T]: V extends T[K] ? K : never
}[keyof T];

type Invert<T extends Record<PropertyKey, PropertyKey>> = {
  [V in T[keyof T]]: KeyFromValue<V, T>
};

使用const o进行测试

代码语言:javascript
复制
const o = {
  a: "x",
  b: "y"
} as const;

// type Invert_o = {x: "a"; y: "b";}
type Invert_o = Invert<typeof o>;

// works
const t: Invert<typeof o> = { x: "a", y: "b" };
// Error: Type '"a1"' is not assignable to type '"a"'.
const t1: Invert<typeof o> = { x: "a1", y: "b" };

使用返回类型Invert<T>,以与上面相同的方式声明invert函数。

Playground

票数 7
EN

Stack Overflow用户

发布于 2020-09-30 05:11:54

有了TypeScript 4.1对Key Remapping in Mapped Types的支持,这变得相当简单

代码语言:javascript
复制
const o = {
    a: 'x',
    b: 'y',
} as const;

declare function invert<
    T extends Record<PropertyKey, PropertyKey>
>(obj: T): {
    [K in keyof T as T[K]]: K
};

let s = invert(o);  // type is { readonly x: "a"; readonly y: "b"; }

playground

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56415826

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档