Skip to content

Instantly share code, notes, and snippets.

@stephenh
Created September 18, 2019 21:12
Show Gist options
  • Save stephenh/3bd0a2fca083033591b835b438801574 to your computer and use it in GitHub Desktop.
Save stephenh/3bd0a2fca083033591b835b438801574 to your computer and use it in GitHub Desktop.
interface AstNode<T> {
value: T;
}
const n1: AstNode<number> = { value: 1 };
const n2: AstNode<string> = { value: "asdf" };
// https://github.com/microsoft/TypeScript/pull/26063 says that if T is a tuple
// type, the mapped type will map each specific type in the tuple.
type Values<T> = { [P in keyof T]: T[P] extends AstNode<infer V> ? V : never };
function node<T, D extends AstNode<any>[], A extends Values<D>>(deps: D | [never], fn: (...args: A) => T): AstNode<T> {
const values = (deps as Array<AstNode<any>>).map(d => d.value) as A;
return { value: fn(...values) };
}
function node2<T, A extends any[]>(
deps: { [K in keyof A]: AstNode<A[K]> } | [never],
fn: (...args: A) => T,
): AstNode<T> {
const values = (deps as Array<AstNode<any>>).map(d => d.value) as A;
return { value: fn(...values) };
}
const n3: AstNode<string> = node([n1, n2], (v1, v2) => {
const v1n: number = v1; // v1 is string | number
const v2s: string = v2; // v2 is string | number
return String(v1) + String(v2);
});
const n4: AstNode<string> = node2([n1, n2], (v1, v2) => {
const v1n: number = v1; // v1 is string | number
const v2s: string = v2; // v2 is string | number
return String(v1) + String(v2);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment