Created
May 2, 2018 21:09
-
-
Save fearthecowboy/5ce5376276cd18bdd9065e56fd7ad47a to your computer and use it in GitHub Desktop.
Typescript conditional types oddity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface Dictionary<T> { | |
[key: string]: T; | |
} | |
export interface Pair<KEY, VALUETYPE> { | |
key: KEY; | |
value: VALUETYPE; | |
} | |
function* itemsa<V>(array: Array<V>): Iterable<Pair<number, V>> { | |
for (let key = 0; key < array.length; key++) { | |
yield { key, value: array[key] }; | |
} | |
} | |
function* itemsd<V>(dictionary: Dictionary<V>): Iterable<Pair<string, V>> { | |
if (dictionary) { | |
for (const key of Object.getOwnPropertyNames(dictionary)) { | |
yield { key, value: dictionary[key] }; | |
} | |
} | |
} | |
export function* values<T>(dictionary?: Dictionary<T> | Array<T>): Iterable<T> { | |
if (Array.isArray(dictionary)) { | |
for (let key = 0; key < dictionary.length; key++) { | |
yield dictionary[key]; | |
} | |
return; | |
} | |
if (dictionary) { | |
for (const key of Object.getOwnPropertyNames(dictionary)) { | |
yield dictionary[key]; | |
} | |
} | |
} | |
function* akeys<V>(array: Array<V>): Iterable<number> { | |
for (let key = 0; key < array.length; key++) { | |
yield key; | |
} | |
} | |
function* dkeys<V>(dictionary?: Dictionary<V>): Iterable<string> { | |
if (dictionary) { | |
for (const key of Object.getOwnPropertyNames(dictionary)) { | |
yield key; | |
} | |
} | |
} | |
export function keys<V, T extends (Dictionary<V> | Array<V>)>(dictionary?: T): T extends Dictionary<V> ? Iterable<string> : Iterable<number> { | |
return Array.isArray(dictionary) ? | |
<T extends Dictionary<V> ? Iterable<string> : Iterable<number>>akeys(dictionary) : | |
<T extends Dictionary<V> ? Iterable<string> : Iterable<number>>dkeys((<Dictionary<V>>dictionary)); | |
} | |
export function length<T>(dictionary?: Dictionary<T> | Array<T>): number { | |
if (Array.isArray(dictionary)) { | |
return dictionary.length; | |
} | |
return dictionary ? Object.getOwnPropertyNames(dictionary).keys.length : 0; | |
} | |
// usage: | |
const dict = { | |
age: 100, | |
name: "garrett" | |
} | |
const arr = ["every", "good", "boy", "deserves", "fudge"]; | |
for( const each of keys(dict)) { | |
console.log(each); | |
} | |
for( const each of keys(arr)) { | |
console.log(each); | |
} | |
for (const each of values(dict)) { | |
console.log(each); | |
} | |
for (const each of values(arr)) { | |
console.log(each); | |
} | |
for (const each of items(dict)) { | |
// type of each is Pair<string, string|number> | |
console.log(each); | |
} | |
for (const each of items(arr)) { | |
// type of each is Pair<number, string> | |
console.log(each); | |
} | |
for (const each of items_bad(dict)) { | |
// type of each is Pair<string, {}> | |
console.log(each); | |
} | |
for (const each of items_bad(arr)) { | |
// type of each is Pair<number, {}> | |
console.log(each); | |
} | |
export function items<V, T extends (Array<V> | Dictionary<V>)>(input?: T & (Array<V> | Dictionary<V>)): T extends Dictionary<V> ? Iterable<Pair<string, V>> : Iterable<Pair<number, V>> { | |
return Array.isArray(input) ? | |
<T extends Dictionary<V> ? Iterable<Pair<string, V>> : Iterable<Pair<number, V>>>itemsa(input) : | |
<T extends Dictionary<V> ? Iterable<Pair<string, V>> : Iterable<Pair<number, V>>>itemsd(<Dictionary<V>>input); | |
} | |
// when I comment out the '& (Array<V> | Dictionary<V>)' form the parameter | |
// the return type goes to Pair<keytype,{}> -- WHY? | |
export function items_bad<V, T extends (Array<V> | Dictionary<V>)>(input?: T /* & (Array<V> | Dictionary<V>) */ ): T extends Dictionary<V> ? Iterable<Pair<string, V>> : Iterable<Pair<number, V>> { | |
return Array.isArray(input) ? | |
<T extends Dictionary<V> ? Iterable<Pair<string, V>> : Iterable<Pair<number, V>>>itemsa(input) : | |
<T extends Dictionary<V> ? Iterable<Pair<string, V>> : Iterable<Pair<number, V>>>itemsd(<Dictionary<V>>input); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment