首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在TypeScript中编写生成双射的函数的函数签名?

如何在TypeScript中编写生成双射的函数的函数签名?
EN

Stack Overflow用户
提问于 2020-10-30 11:42:07
回答 1查看 53关注 0票数 0

我有一个函数,它获取一张地图并生成地图的双向投影:

代码语言:javascript
复制
 export function keyTextBijection(map) {
  const bijection = {};
  Object.keys(map).forEach(key => {
    bijection[key] = map[key];
    bijection[map[key]] = key;
  });
  return bijection;
}

如何在TypeScript中优雅地对函数进行签名?

EN

回答 1

Stack Overflow用户

发布于 2020-10-30 12:26:17

它有助于编写一个类型函数,将像{a: "A", b: "B"}这样的类型转换为与之相反的类型{A: "a", B: "b"}。TypeScript 4.1将通过microsoft/TypeScript#40336实现的映射类型as子句简化这一过程

代码语言:javascript
复制
// TS4.1+
type Invert<T extends Record<keyof T, PropertyKey>> = { [K in keyof T as T[K]]: K };

但对于TypeScript 4.0及更低版本,您可以通过使用映射的条件类型在大多数情况下获得合理的等价物:

代码语言:javascript
复制
// TS4.0-
type Invert<T extends Record<keyof T, PropertyKey>> =
    { [K in T[keyof T]]: { [P in keyof T]: K extends T[P] ? P : never }[keyof T] }

在这两种情况下,您都希望keyTextBijection接受T类型的对象并返回T & Invert<T>类型的对象。因为这样的交集看起来很丑陋,所以我通常定义一个名为Id的无操作映射类型,它具有将交集合并到单个类型对象中的效果。(此Idthis question中也称为Expand ):

代码语言:javascript
复制
type Id<T> = T extends infer U ? { [K in keyof U]: U[K] } : any;

所以现在我们可以给keyTextBijection一个调用签名

代码语言:javascript
复制
function keyTextBijection<T extends Record<keyof T, S>, S extends PropertyKey>(
  map: T
): Id<T & Invert<T>>;
function keyTextBijection(map: any) {
    const bijection: any = {};
    Object.keys(map).forEach(key => {
        bijection[key] = map[key];
        bijection[map[key]] = key;
    });
    return bijection;
}

在上面的代码中,S实际上并没有做任何推理工作;它主要是给编译器一个提示,让它尝试将T类型推断为从文字到文字的映射。当您输入{a: "A"}作为map参数时,您希望编译器将类型视为{a: "A"}而不是{a: string},因为后者无法正确反转。

该函数使用单个overload调用签名,以允许实现在类型安全方面不严格,并使用any。(如果不这样做,您将发现自己不得不使用大量的type assertions,因为编译器将无法验证赋值语句的类型安全性)。

让我们测试一下:

代码语言:javascript
复制
const bij = keyTextBijection({ a: "A", b: "B", c: "C" });
/* const bij: {
    a: "A";
    b: "B";
    c: "C";
    A: "a";
    B: "b";
    C: "c";
} */
console.log(bij);
/* {
  "a": "A",
  "A": "a",
  "b": "B",
  "B": "b",
  "c": "C",
  "C": "c"
}  */

bij的类型和值在我看来是正确的。

Playground link to code

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

https://stackoverflow.com/questions/64602432

复制
相关文章

相似问题

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