I can't find a good piece of documentation for this at the moment, but your notWidened()
function works just fine and is not a bug. TypeScript will infer string literals for generic type variables if you constrain the type parameter to string
or a subtype of string
. So <T extends keyof U>
, <T extends string>
, <T extends 'a'|'b'>
, etc. will infer string literals for T
. (You can also infer number
or boolean
literals if you constrain T
similarly).
So your code is just fine as far as I can see; the only thing I might do differently is
type Animal = (typeof animals)[number]
instead of
type Animal = typeof animals[0]
since the 0
th element of animals
is actually 'cat'
, even though you've told TypeScript it is 'cat'|'dog'|...
. Yours is fine, though.
As I commented above, if you want TypeScript to consider animals
to be a tuple where animals[0]
is of type 'cat'
, and animals[1]
is of type 'dog'
, etc., you can use something like the function tuple()
in tuple.ts (UPDATE July 2018, starting in TypeScript 3.0 the compiler will be able to infer tuple types automatically, so the function can be more succinct):
export type Lit = string | number | boolean | undefined | null | void | {};
export const tuple = <T extends Lit[]>(...args: T) => args;
const animals = tuple('cat', 'dog', 'rabbit', 'snake');
type Animal = (typeof animals)[number]; // union type
which might come in handy for you.
TL;DR: ?? your code is fine.
Hope that helps; good luck!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…