Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Simplify handle all types #414

Merged
merged 10 commits into from Jul 2, 2022
2 changes: 1 addition & 1 deletion index.d.ts
Expand Up @@ -38,7 +38,7 @@ export {Entry} from './source/entry';
export {Entries} from './source/entries';
export {SetReturnType} from './source/set-return-type';
export {Asyncify} from './source/asyncify';
export {Simplify} from './source/simplify';
export {Simplify, SimplifyOptions} from './source/simplify';
export {Jsonify} from './source/jsonify';
export {Schema} from './source/schema';
export {LiteralToPrimitive} from './source/literal-to-primitive';
Expand Down
28 changes: 27 additions & 1 deletion source/simplify.d.ts
@@ -1,3 +1,24 @@
import {Class, Constructor} from './basic';

/**
Simplify options.

@param deep - Do the simplification recursively (default: false).
skarab42 marked this conversation as resolved.
Show resolved Hide resolved

@see Simplify
*/
export interface SimplifyOptions {
deep?: boolean;
}

// Flatten a type without worrying about the result.
type Flatten<
AnyType,
Options extends SimplifyOptions = {},
> = Options['deep'] extends true
? {[KeyType in keyof AnyType]: Simplify<AnyType[KeyType], Options>}
: {[KeyType in keyof AnyType]: AnyType[KeyType]};

/**
Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.

Expand Down Expand Up @@ -55,4 +76,9 @@ fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface`

@category Object
*/
export type Simplify<T> = {[KeyType in keyof T]: T[KeyType]};
export type Simplify<
AnyType,
Options extends SimplifyOptions = {},
> = Flatten<AnyType> extends AnyType
skarab42 marked this conversation as resolved.
Show resolved Hide resolved
? Flatten<AnyType, Options>
: AnyType;
35 changes: 35 additions & 0 deletions test-d/simplify.ts
Expand Up @@ -42,3 +42,38 @@ expectType<SomeInterfaceAsTypeWrittenByHand>(valueAsInterface);
expectAssignable<Record<string, unknown>>(valueAsLiteral);
expectAssignable<Record<string, unknown>>(valueAsSimplifiedInterface);
expectNotAssignable<Record<string, unknown>>(valueAsInterface); // Index signature is missing in interface

// Should return the original type if it is not simplifiable, like a function.
type SomeFunction = (type: string) => string;
expectType<Simplify<SomeFunction>>((type: string) => type);

class SomeClass {
id: string;

private readonly code: number;

constructor() {
this.id = 'some-class';
this.code = 42;
}

someMethod() {
return this.code;
}
}

expectType<Simplify<SomeClass>>(new SomeClass());

// Test deep option
// This is mostly visual, move the mouse over "expectAssignable" to see the result.
type PositionAndSize = PositionProps & SizeProps;

interface Node {
parent: PositionAndSize;
child: {parent: PositionAndSize};
}

const node = {parent: flattenProps, child: {parent: flattenProps}};

expectAssignable<Simplify<Node>>(node);
expectAssignable<Simplify<Node, {deep: true}>>(node);