Skip to content

Instantly share code, notes, and snippets.

@kasper573
Created September 8, 2018 12:21
Show Gist options
  • Save kasper573/4b173fa675a37f1a4fef6ef4f1f290df to your computer and use it in GitHub Desktop.
Save kasper573/4b173fa675a37f1a4fef6ef4f1f290df to your computer and use it in GitHub Desktop.
function getInstances<T, C, B> (
target: T,
clazz: Class<C>,
transform: (instance: C) => B = noop
) {
const transformed: Record<keyof SubType<T, C>, B> = {} as any;
for (const key in target) {
const value = target[key];
if (value instanceof clazz) {
(transformed as any)[key] = transform(value);
}
}
return transformed;
}
function getInstancesRecursive<T, C, B> (
target: T,
clazz: Class<C>,
transform: (instance: C) => B = noop
) {
type First = Record<keyof SubType<T, C>, B>; // Instances
type Second = Record<keyof SubType<T, Record<string, C>>, Record<string, B>>; // Records of instances
type Double = First & Second;
const transformed: Double = {} as any;
// Find the instances
Object.assign(transformed, getInstances(target, clazz, transform));
// Find the records of instances
for (const key in target) {
const value = target[key];
if (isPlainObject(value)) {
(transformed as any)[key] = getInstances(value, clazz, transform);
}
}
return transformed;
}
function noop (val: any) {
return val;
}
type SubType<Base, Condition> = Pick<Base, {
[Key in keyof Base]: Base[Key] extends Condition ? Key : never
}[keyof Base]>;
@lumie1337
Copy link

lumie1337 commented Sep 8, 2018

// WIP Untested

// Keys that extend Condition
type K<Base, Condition> = {
	[Key in keyof Base]: Base[Key] extends Condition ? Key : never
}[keyof Base]

// Keys that extend Condition or have a non empty Hierarchy that includes elements that extend Condition
type KR<Base, Condition> = K<Base, Condition> | {
	[Key in keyof Base]: Base[Key] extends object ?
		(IsNotNeverType<KR<Base[Key], Condition>> ? Key : never) :
		never
}[keyof Base]

// Helper to match on non-empty unions
type IsNotNeverType<T> = [T] extends [never] ? never : true;

// Hierarchy with Condition applied and then Mapped to type Mapped
type SubTypeRefMapped<Base, Condition, Mapped> = {
	[Key in KR<Base, Condition>]: Base[Key] extends Condition ? Mapped : SubTypeRefMapped<Base[Key], Condition, Mapped>
}

@lumie1337
Copy link

type SubTypeRefMappedCrud<Base> = {
	[Key in KR<Base, Crud<any>>]: Base[Key] extends Crud<infer Mapped> ? Mapped : SubTypeRefMappedCrud<Base[Key]>
}

@lumie1337
Copy link

lumie1337 commented Sep 8, 2018

Full Example

type K<Base, Condition> = {
	[Key in keyof Base]: Base[Key] extends Condition ? Key : never
}[keyof Base]

type KR<Base, Condition> = K<Base, Condition> | {
	[Key in keyof Base]: Base[Key] extends object ?
		[KR<Base[Key], Condition>] extends [never] ? never : Key :
		never
}[keyof Base]

interface Crud<A, B, C> {
    a: A;
    b: B;
    c: C;
}

type SubTypeRefMappedCrud<Base> = {
	[Key in KR<Base, Crud<any, any, any>>]: Base[Key] extends Crud<any, any, any> ? Base[Key]['a'] : SubTypeRefMappedCrud<Base[Key]>
}

Usage Example

type A = {
    a: Crud<string, number, string>,
    b: {
        c: Crud<number, number, number>
    }
}

type B = SubTypeRefMappedCrud<A>

let b: B
b.b.c // is type number

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment