如何消除部分索引类型中未定义的联合?

How do I eliminate union with undefined in partial index type?

我有一个 objectMap() 函数,它接受一个对象,对每个值应用一个函数,return 是一个具有相同键但不同值的对象。我为此写了以下声明:

declare function objectMap<TInputObject, TOutputValue>(
        target: TInputObject,
        callback: (currentValue: TInputObject[keyof TInputObject]) => TOutputValue,
    ): {[k in keyof TInputObject]: TOutputValue};

我希望这会使用在对象值中找到的类型调用回调函数,并且 return 一个与输入对象具有相同键结构的对象。这适用于大多数类型的对象,例如简单映射甚至字符串文字的并集:

type in1 = {[k: string]: string}

type keys = 'a' | 'b' | 'c'
type in2 = {[k in keys]: number}

但它分解为字符串文字联合类型的可选键:

type keys = 'a' | 'b' | 'c'
type in = {[key in keys]?: number }

在这种情况下,当我尝试使用函数时:

const obj : {[key in keys]?: number} = {a: 1, b: 2}
const result = objectMap(obj, x => x+1)

变量x获得类型number | undefined(即使所有存在的键都有一个实际的数值),并且result除了可选键。

如何更改 objectMap() 的声明以获得预期结果,其中 x 只是 numberresult{[k in keys]?: number

我想这取决于 objectMap() 的实施;假设对于 Object.keys(target) 中的每个键 k,您首先要确保 target[k] 不是 undefined(如果 k 是可选键,则可能发生这种情况)在调用 callback 之前。如果是这样,那么您可以稍微修改 objectMap() 的签名,以便 callback 参数不需要担心 undefined 参数,通过使用 predefined conditional type Exclude<U, X>... 它采用联合类型 U 并删除可分配给 X 的任何成分,如下所示:

function objectMap<I, O>(
  target: I,
  callback: (currentValue: Exclude<I[keyof I], undefined>) => O
) {
  const ret = {} as { [K in keyof I]: O };
  let k: keyof I;
  for (k in target) {
    const tk = target[k];
    if (typeof tk !== "undefined") {
      ret[k] = callback(tk as Exclude<I[keyof I], undefined>);
    }
  }
  return ret;
}

鉴于该签名,您现在可以像这样使用 objectMap()

interface A {
  a?: number;
  b: number;
  c?: number;
}
const a: A = { a: 1, b: 2 };
const result = objectMap(a, x => x.toFixed());
// const result: {a?: string | undefined, b: string, c?: string | undefined }
console.log(result); // {a: "1", b: "2"}

因此在这种情况下,A 接口具有可选的数字属性 "a""c",以及必需的数字 属性 "b"。回调的类型为(x: number)=>string,返回的结果类型具有相同的可选和必需的属性键,但值是string类型。 (请注意,{a?: string | undefined, b: string, c?: string | undefined} 类型与 {a?: string, b: string, c?: string} 类型相同)如果编译器在编译时只知道 a 值是可赋值的,那么这就是编译器所能做的最好的事情至 A.

好的,希望对您有所帮助;祝你好运!

Link to code