Add ConditionalSimplify and ConditionalSimplifyDeep types (#442)

This commit is contained in:
skarab42 2022-08-24 22:28:10 +02:00 committed by GitHub
parent bbccfb88a0
commit beaabe1821
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 113 additions and 0 deletions

32
source/conditional-simplify.d.ts vendored Normal file
View File

@ -0,0 +1,32 @@
/**
Simplifies a type while including and/or excluding certain types from being simplified. Useful to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
This type is **experimental** and was introduced as a result of this {@link https://github.com/sindresorhus/type-fest/issues/436 issue}. It should be used with caution.
@internal
@experimental
@see Simplify
@category Object
*/
export type ConditionalSimplify<Type, ExcludeType = never, IncludeType = unknown> = Type extends ExcludeType
? Type
: Type extends IncludeType
? {[TypeKey in keyof Type]: Type[TypeKey]}
: Type;
/**
Recursively simplifies a type while including and/or excluding certain types from being simplified.
This type is **experimental** and was introduced as a result of this {@link https://github.com/sindresorhus/type-fest/issues/436 issue}. It should be used with caution.
See {@link ConditionalSimplify} for usages and examples.
@internal
@experimental
@category Object
*/
export type ConditionalSimplifyDeep<Type, ExcludeType = never, IncludeType = unknown> = Type extends ExcludeType
? Type
: Type extends IncludeType
? {[TypeKey in keyof Type]: ConditionalSimplifyDeep<Type[TypeKey], ExcludeType, IncludeType>}
: Type;

View File

@ -0,0 +1,81 @@
import {expectError, expectType} from 'tsd';
import type {ConditionalSimplify, ConditionalSimplifyDeep} from '../source/conditional-simplify';
type Position = {top: number; left: number};
type Size = {width: number; height: number};
// In your editor, hovering over `PositionAndSizeSimplified` will show a simplified object with all the properties.
type PositionAndSizeIntersection = Position & Size;
type PositionAndSizeSimplified = ConditionalSimplify<PositionAndSizeIntersection>;
const position = {top: 120, left: 240};
const size = {width: 480, height: 600};
const positionAndSize = {...position, ...size};
expectType<PositionAndSizeSimplified>(positionAndSize);
// Exclude function type to be simplified.
type SomeFunction = (type: string) => string;
type SimplifiedFunctionFail = ConditionalSimplify<SomeFunction>; // Return '{}'
type SimplifiedFunctionPass = ConditionalSimplify<SomeFunction, Function>; // Return '(type: string) => string'
declare const simplifiedFunctionFail: SimplifiedFunctionFail;
declare const simplifiedFunctionPass: SimplifiedFunctionPass;
expectError<SomeFunction>(simplifiedFunctionFail);
expectType<SomeFunction>(simplifiedFunctionPass);
// Should simplify interface deeply.
interface SomeNode {
parent: PositionAndSizeIntersection;
childs: Array<{parent: PositionAndSizeIntersection}>;
}
// In your editor, hovering over `SomeNodeSimplified` will show a simplified object with all the properties.
type SomeNodeSimplified = ConditionalSimplifyDeep<SomeNode>;
const someNode = {parent: positionAndSize, childs: [{parent: positionAndSize}, {parent: positionAndSize}]};
expectType<SomeNodeSimplified>(someNode);
// Should simplify interface deeply excluding Function type.
interface MovablePosition extends Position {
move(position: Position): Position;
}
interface MovableCollection {
position: MovablePosition;
top: {position: MovablePosition; size: Size};
left: {position: MovablePosition; size: Size};
}
type MovableNodeSimplifiedFail = ConditionalSimplifyDeep<MovableCollection>;
type MovableNodeSimplifiedPass = ConditionalSimplifyDeep<MovableCollection, Function>;
declare const movableNodeSimplifiedFail: MovableNodeSimplifiedFail;
declare const movableNodeSimplifiedPass: MovableNodeSimplifiedPass;
expectError<MovableCollection>(movableNodeSimplifiedFail);
expectType<MovableCollection>(movableNodeSimplifiedPass);
const movablePosition = {
top: 42,
left: 42,
move(position: Position) {
return position;
},
};
const movableNode = {
position: movablePosition,
top: {position: movablePosition, size},
left: {position: movablePosition, size},
};
expectType<MovableNodeSimplifiedPass>(movableNode);
// Should exclude `Function` and `Size` type (mainly visual, mouse over the statement).
type ExcludeFunctionAndSize1 = ConditionalSimplifyDeep<MovableCollection, Function | Size>;
expectType<ExcludeFunctionAndSize1>(movableNode);
// Same as above but using `IncludeType` parameter (mainly visual, mouse over the statement).
type ExcludeFunctionAndSize2 = ConditionalSimplifyDeep<MovableCollection, Function, MovableCollection | Position>;
expectType<ExcludeFunctionAndSize2>(movableNode);