简体   繁体   English

在 Typescript 联合中键入属性的 getter

[英]Typing getter of a property in a Typescript union

I have theses Typescript types:我有这些 Typescript 类型:

type A = {
  a: string
}

type B = {
  b: number,
}

type C = number;

type U = A | B | C;

I'm trying to write the function that, given a property of one of U types, return the property value or undefined .我正在尝试编写 function ,给定U类型之一的属性,返回属性值或undefined

In Javascript, it would be something like that:在 Javascript 中,它会是这样的:

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

    return undefined;
  }  
}

Example:例子:

const u: U = ...;

const a: string | undefined = getProp('a')(u);

I've tried this:我试过这个:

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);

But this is not valid.但这是无效的。 I think I have to find an alternative for U[P] if I want to type this strange function properly but I don't see what.如果我想正确输入这个奇怪的 function,我想我必须找到U[P]的替代方法,但我看不到是什么。 Any idea?任何想法?

From the caller's side of view, you probably want getProp() to return a function which returns IdxUnion<U, P> , where IdxUnion is defined like this:从调用者的角度来看,您可能希望getProp()返回一个 function ,它返回IdxUnion<U, P> ,其中IdxUnion定义如下:

type IdxUnion<T, K extends PropertyKey> =
  T extends any ? K extends keyof T ? T[K] : undefined : never;

This will do the lookup for each member of a union T and return either T[K] or undefined depending on whether or not K is a key of that member of T .这将对联合T的每个成员进行查找,并根据K是否是T的该成员的键返回T[K]undefined This should fix things from the call side, mostly:这应该从调用端解决问题,主要是:

const a = getProp('a')(u); // string | undefined

I say "mostly" because the function implementation doesn't quite do what you're saying it will do given the signature: if u is a number and not an object, you are always returning undefined at runtime, but number has keys such as toFixed , so you'd expect getProp('toFixed')(123) to be a function.我说“主要”是因为u numberundefined完全按照你所说number那样做toFixed ,因此您希望getProp('toFixed')(123)是 function。 This is mostly not a problem for your particular U , since A and B will give you the undefined that actually comes out, but it's weird.对于您的特定U来说,这基本上不是问题,因为AB会给您实际出现的undefined ,但这很奇怪。 So be careful:所以要小心:

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

Inside the implemementation of getProp() , things are tougher.getProp()的实现内部,事情变得更加艰难。 The compiler generally has a hard time evaluating the type safety of operations that occur on unspecified generic types, especially conditional types.编译器通常很难评估发生在未指定泛型类型(尤其是条件类型)上的操作的类型安全性。 Your best bet here is probably to use type assertions to tell the compiler that you know what you're doing:您最好的选择可能是使用类型断言来告诉编译器您知道自己在做什么:

if (typeof thing === "object" && prop in thing) {
  return thing[prop as keyof typeof thing]; // assert
}
return undefined as IdxUnion<U, P>; // assert

Anyway, hope that helps;无论如何,希望有所帮助; good luck!祝你好运!

Playground link to code Playground 代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM