typescript 使函数接受泛型输入,返回具有相同键的值,但具有来自另一类型的值

oalqel3c  于 2023-02-05  发布在  TypeScript
关注(0)|答案(1)|浏览(125)

我有以下类型

type A = {
  foo: number
  bar: number
}

type B = {
  foo: string
  bar: string
}

我想写一个函数f(),它接受一个完全或部分类型为A的参数,并输出一个对象,该对象具有相同的键,但类型为B。
例如,

f(a) = {foo: 1, bar: 2}
// should have return type {foo: string, bar: string}
f(a) = {foo: 1}
// should have return type {foo: string}
f(a) = {bar: 1}
// should have return type {bar: string}

我尝试过使用泛型,但是由于typescript不检查额外的字段,所以当我使用keyof时,我得到了一个错误:

function f<T extends A>(input: T): {[K in keyof T]: B[K]} {
  //      Type 'K' cannot be used to index type 'B' ^^^^^

  // ... function implementation here
}

如果这个解决方案要起作用,我将不得不以某种方式限制T仅为A类型的子集,尽管我还没有找到一种方法来使编译器理解keyof T可以索引A
我最接近的方法是使用Partial,但这并不是我想要的行为:

function f(input: Partial<A>): Partial<B> {
  // mock implementation, output does not matter, asking about types here
  const res: Partial<B> = {};
  let k: keyof typeof input;
  for (k in input) {
    const v = input[k];
    res[k] = parseInt(v ?? "0");
  }
  return res;
}

这是不正确的,因为以下输入都给出相同类型的输出:

const a = f({})
const b = f({foo: 1})
const c = f({bar: 2})
// a, b, c all have type {foo?: number, bar?: number)

// should be:
// a: {}
// b: {foo: string}
// c: {bar: string}

我所要求的东西现在在Typescript中是否可行?任何解决方案/变通方法都将不胜感激。

jvlzgdj9

jvlzgdj91#

我的建议是将函数f()generic设置为input参数的键K的类型,然后可以使用Pick<T, K>实用程序类型将input表示为Pick<A, K>,将输出类型表示为Pick<B, K>

declare function f<K extends keyof A>(input: Pick<A, K>): Pick<B, K>;

或者,您可以内联Pick的定义以获得以下版本:

declare function f<K extends keyof A>(input: { [P in K]: A[K] }): { [P in K]: B[K] };

让我们来测试一下:

const b0 = f({ foo: 1, bar: 2 });
/* const b0: {
    foo: string;
    bar: string;
} */

const b1 = f({ foo: 1 });
/* const b1: {
    foo: string;
} */

const b2 = f({ bar: 1 });
/* const b2: {
    bar: string;
} */

看起来不错。
Playground代码链接

相关问题