Issue when using distributive conditional types combined with generic method

前端 未结 2 587
轻奢々
轻奢々 2020-12-12 01:46

I\'ve been trying to make a generic function which receives and object T and receives a string property name of that object T.

I used https://www.typescriptlang.org/d

相关标签:
2条回答
  • 2020-12-12 02:17

    The compiler generally cannot determine assignability of unresolved conditional types (that is, conditional types which cannot be eagerly evaluated because at least one of the T or U in T extends U ? V : W is not yet fully specified).

    This is more of a design limitation than a bug (see Microsoft/TypeScript#30728); the compiler is not going to be as smart as a human being (note to self: come back here when the machine uprising happens and edit this) so we shouldn't expect it to just "notice" that T[TypedPropertyName<T,P>] extends P should always be true. We could write a particular heuristic algorithm to detect the situation and perform the desired reduction, but it would have to be able to run very quickly so that it doesn't degrade compile times for the 99% of the time when it wouldn't be useful.

    Can anyone point me in the direction of making the generic version work (without any hacks)

    That really depends on what you consider a hack. The absolute simplest thing to do is to use a type assertion, which is explicitly intended for times when you know something is type safe but the compiler isn't able to figure it out:

    function generic<T>(form: T, field: StringPropertyNames<T>): string {
      return form[field] as any as string;  // I'm smarter than the compiler                                                                     
    0 讨论(0)
  • 2020-12-12 02:27

    Honestly, I do not know what the issue is. You might try filing a issue on their GH. However, I do know that the following does work without explicitly specifying the return type:

    function generic<T>(form: T, field: StringPropertyNames<T>) {
      return form[field];
    }
    

    and it even correctly types the return value as a string:

    const test = {
      a: "b",
      c: 1,
      "other": "blah"
    }
    generic(test, "a").charAt(0) //passes - "b"
    generic(test, "a") * 5 // fails - function result is not a number
    generic(test, "c") //fails - "c" is not assignable to "a" | "other"
    

    I would additionally recommend this addition to make sure the first argument must be an object:

    function generic<T extends object>(form: T, field: StringPropertyNames<T>) {
      return form[field];
    }
    
    0 讨论(0)
提交回复
热议问题