在Typescript联合中键入属性的getter

在Typescript联合中键入属性的getter,typescript,types,Typescript,Types,我有这些类型的脚本类型: type A = { a: string } type B = { b: number, } type C = number; type U = A | B | C; 我试图编写一个函数,给定U类型之一的属性,返回属性值或未定义的 在Javascript中,应该是这样的: function getProp(prop: P) { return (thing) => { if (typeof thing === 'object' &

我有这些类型的脚本类型:

type A = {
  a: string
}

type B = {
  b: number,
}

type C = number;

type U = A | B | C;
我试图编写一个函数,给定
U
类型之一的属性,返回属性值或
未定义的

在Javascript中,应该是这样的:

function getProp(prop: P) {
  return (thing) => {
    if (typeof thing === 'object' && prop in thing) {
      return thing[prop]
    }

    return undefined;
  }  
}
例如:

const u: U = ...;

const a: string | undefined = getProp('a')(u);
我试过这个:

type KeysOfUnion<T> = T extends any ? keyof T : never; // because `keyof U` return `never`

function getProp<P extends KeysOfUnion<U>>(prop: P) {
    return (thing: U): U[P] => { // error: `Type 'P' cannot be used to index type 'U'.`
        if (typeof thing === 'object' && prop in thing) {
          return thing[prop]; // error: Type 'P' cannot be used to index type 'A | B'
        }

        return undefined; // error: Type 'undefined' is not assignable to type 'U[P]'.
    }
}

const a: string | undefined = getProp('a')(u);
typekeysofunion=T扩展了什么?T的键:从不;//因为'keyof'return'永远不会`
函数getProp(prop:P){
return(thing:U):U[P]=>{//error:'Type'P'不能用于索引类型'U'`
if(typeof thing==='object'&&prop in thing){
return thing[prop];//错误:类型“P”不能用于索引类型“A | B”
}
return undefined;//错误:类型“undefined”不能分配给类型“U[P]”。
}
}
常数a:string | undefined=getProp('a')(u);

但这是无效的。如果我想正确地键入这个奇怪的函数,我想我必须为
U[P]
找到一个替代方法,但我不知道是什么。有什么想法吗?

从调用方的角度来看,您可能希望
getProp()
返回一个返回
IdxUnion
的函数,其中
IdxUnion
的定义如下:

type IdxUnion<T, K extends PropertyKey> =
  T extends any ? K extends keyof T ? T[K] : undefined : never;
我之所以说“大部分”,是因为函数实现并不像您所说的那样,在给定签名的情况下它会做:如果
u
是一个
number
而不是一个对象,您总是在运行时返回
未定义的
,但是
number
toFixed
等键,所以您希望
getProp('toFixed'))(123)
作为一个函数。这对于您的特定
U
来说基本上不是问题,因为
a
B
会给您实际出现的
未定义的
,但这很奇怪。因此请小心:

const hmm = getProp('toFixed')(123);
// ((fractionDigits?: number | undefined) => string) | undefined

getProp()
的实现中,事情更为棘手。编译器通常很难评估在未指定泛型类型(尤其是条件类型)上发生的操作的类型安全性。您在这里的最佳选择可能是告诉编译器您知道自己在做什么:

if (typeof thing === "object" && prop in thing) {
  return thing[prop as keyof typeof thing]; // assert
}
return undefined as IdxUnion<U, P>; // assert
if(typeof thing==“object”&&prop in thing){
返回thing[prop as key of typeof thing];//断言
}
返回未定义的IdxUnion;//断言

不管怎样,希望这有帮助,祝你好运


感谢@jcalz提供的详细答案,并指出我的实现中缺少了一些键,如
toFixed
。完全忘记了它们!
if (typeof thing === "object" && prop in thing) {
  return thing[prop as keyof typeof thing]; // assert
}
return undefined as IdxUnion<U, P>; // assert