Skip to content

Extending empty tuple in generic functions causes compiler to infer arrays as tuples #31434

Closed
@ipotuzhnov

Description

@ipotuzhnov

TypeScript Version: 3.4.5

Search Terms:
empty tuple, type inference, generic function

Code
Basically I'm writing a generic function with dynamic type mapping. I think this use case is pretty common for database drivers and JSON validators and I found some related issues. There is a workaround and I want to confirm whether it is intended behavior or a bug.

interface TypeMap { STRING: string; NUMBER: number;}
type MapTypes<T> = {
  [P in keyof T]: T[P] extends keyof TypeMap ? TypeMap[T[P]] : never
};

declare function fromArray<T extends ReadonlyArray<keyof TypeMap>>(
  types: T, params: MapTypes<T>): void;

fromArray(['STRING', 'NUMBER', 'STRING'], ['abc', 123, 'xyz']);  // ok
// the default behavior is to infer types in array as type union
fromArray(['STRING', 'NUMBER', 'STRING'], ['abc', '123', 'xyz']);  // no error
fromArray(['STRING', 'NUMBER', 'STRING'] as const, ['abc', '123', 'xyz']);  // error

declare function fromTuple<T extends([] | ReadonlyArray<keyof TypeMap>)>(
  types: T, params: MapTypes<T>): void;

fromTuple(['STRING', 'NUMBER', 'STRING'], ['abc', 123, 'xyz']);  // ok
// T extends([]|MyType) cases the compiler to infer array as tuple
fromTuple(['STRING', 'NUMBER', 'STRING'], ['abc', '123', 'xyz']);  // error
fromTuple(['STRING', 'NUMBER', 'STRING'] as const, ['abc', '123', 'xyz']);  // error

Expected behavior:
Type of the array literal is inferred as array of union type.

Actual behavior:
Type of the array literal is inferred as tuple when T extends []|MyType is used in generic function.
I'd prefer it to be the expected behavior, but I didn't find any tests for that use case.

Playground Link:
You can see the same behavior in the playground

Related Issues:
#13151
#22679

Related PR
This PR includes a similar test, but it there is no test for empty tuple and array combination #26676

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions