0.3.0 • Published 11 months ago

@ktarmyshov/typesafe-utilities v0.3.0

Weekly downloads
-
License
MIT
Repository
github
Last release
11 months ago

NPM Version CI Quality Gate Status Bugs Code Smells Duplicated Lines (%) Socket Badge

typesafe-utilities

Some very specific type-safe utilities that are not available in type-fest (very extensive).

Usage

Property paths

Difference to type-fest:

  • Array property path can be specified like prop1[].prop2 (without index)
  • Does not support tuples
  • Supports only Record<string, unknown>
  • Somewhat better auto-complete for nested arrays of objects
/* eslint-disable @typescript-eslint/no-unused-vars */
import { PropertyPaths } from '../src/paths';

type TestType = {
	prop1: string;
	prop2: number;
	propArr: string[];
	propArr2: {
		propArr3: string[];
	};
	propArr4: {
		propArr5: string[];
	}[];
	prop3: {
		prop4: string;
		prop5: {
			prop6: string[];
		};
	}[];
};

type TestTypePropertyPaths = PropertyPaths<TestType>;

const test1: TestTypePropertyPaths = 'prop1';
const test2: TestTypePropertyPaths = 'prop2';
const test3: TestTypePropertyPaths = 'propArr';
const test4: TestTypePropertyPaths = 'propArr[]';
const test5: TestTypePropertyPaths = 'propArr[0]';
const test6: TestTypePropertyPaths = 'propArr2.propArr3';
const test7: TestTypePropertyPaths = 'propArr2.propArr3[]';
const test8: TestTypePropertyPaths = 'propArr2.propArr3[0]';
const test9: TestTypePropertyPaths = 'propArr4';
const test10: TestTypePropertyPaths = 'propArr4[]';
const test11: TestTypePropertyPaths = 'propArr4[0]';
const test12: TestTypePropertyPaths = 'propArr4[].propArr5';
const test13: TestTypePropertyPaths = 'propArr4[].propArr5[]';
const test14: TestTypePropertyPaths = 'propArr4[].propArr5[0]';
const test15: TestTypePropertyPaths = 'propArr4[0].propArr5';
const test16: TestTypePropertyPaths = 'propArr4[0].propArr5[]';
const test17: TestTypePropertyPaths = 'propArr4[0].propArr5[0]';
const test18: TestTypePropertyPaths = 'prop3';
const test19: TestTypePropertyPaths = 'prop3[]';
const test21: TestTypePropertyPaths = 'prop3[].prop4';
const test22: TestTypePropertyPaths = 'prop3[].prop5';
const test23: TestTypePropertyPaths = 'prop3[].prop5.prop6';
const test24: TestTypePropertyPaths = 'prop3[].prop5.prop6[]';
const test25: TestTypePropertyPaths = 'prop3[0]';
const test26: TestTypePropertyPaths = 'prop3[0].prop4';
const test27: TestTypePropertyPaths = 'prop3[0].prop5';
const test28: TestTypePropertyPaths = 'prop3[0].prop5.prop6';
const test29: TestTypePropertyPaths = 'prop3[0].prop5.prop6[]';
const test30: TestTypePropertyPaths = 'prop3[0].prop5.prop6[0]';

// @ts-expect-error: Invalid property path
const test_e1: TestTypePropertyPaths = ''; // should be error
// @ts-expect-error: Invalid property path
const test_e2: TestTypePropertyPaths = 'prop1.prop2'; // should be error
// @ts-expect-error: Invalid property path
const test_e3: TestTypePropertyPaths = 'prop1[]'; // should be error
// @ts-expect-error: Invalid property path
const test_e4: TestTypePropertyPaths = 'prop1[0]'; // should be error
// @ts-expect-error: Invalid property path
const test_e5: TestTypePropertyPaths = 'propArr.'; // should be error

DeepPartial

/* eslint-disable @typescript-eslint/no-unused-vars */
import { type DeepPartial } from '../src/partial';

type TestType = {
	prop1: string;
	prop2: number;
	propArr: string[];
	propArr2: {
		propArr3: string[];
	};
	propArr4: {
		propArr5: string[];
	}[];
	prop3: {
		prop4: string;
		prop5: {
			prop6: string[];
		};
	}[];
};

type TestTypeDeepPartial = DeepPartial<TestType>;
const test1: TestTypeDeepPartial = {
	prop1: 'test',
	prop2: 123
};
const test2: TestTypeDeepPartial = {
	propArr: ['test1', 'test2'],
	propArr2: {}
};
const test3: TestTypeDeepPartial = {
	propArr2: {
		propArr3: ['test1', 'test2']
	}
};
const test4: TestTypeDeepPartial = {
	propArr4: [{}]
};
const test5: TestTypeDeepPartial = {
	propArr4: [
		{
			propArr5: ['test1', 'test2']
		}
	]
};
const test6: TestTypeDeepPartial = {
	prop3: [{}]
};
const test7: TestTypeDeepPartial = {
	prop3: [
		{
			prop4: 'test',
			prop5: {}
		}
	]
};
const test8: TestTypeDeepPartial = {
	prop3: [
		{
			prop4: 'test',
			prop5: {
				prop6: ['test1', 'test2']
			}
		}
	]
};
const test9: TestTypeDeepPartial = {
	prop3: [
		{
			prop4: 'test',
			prop5: {
				prop6: ['test1', 'test2']
			}
		},
		{}
	]
};

Filter & DeepFilter

/* eslint-disable @typescript-eslint/no-unused-vars */
import {
	DeepFilter,
	type FilterInclude,
	type FilterIncludeKeys,
	type NonNeverKeys,
	type OmitNever
} from '../src/filter';
import { type Equal, type Expect } from './helpers';

type TestType = {
	a: string;
	b: number;
	c: boolean;
};

type asserts_FilterKeys = [
	Expect<Equal<FilterIncludeKeys<TestType, string | number>, 'a' | 'b'>>,
	Expect<Equal<FilterIncludeKeys<TestType, string>, 'a'>>,
	Expect<Equal<FilterIncludeKeys<TestType, number>, 'b'>>,
	Expect<Equal<FilterIncludeKeys<TestType, boolean>, 'c'>>,
	Expect<Equal<FilterIncludeKeys<TestType, unknown>, 'a' | 'b' | 'c'>>
];

type asserts_Filter = [
	Expect<Equal<FilterInclude<TestType, string | number>, { a: string; b: number }>>,
	Expect<Equal<FilterInclude<TestType, string>, { a: string }>>,
	Expect<Equal<FilterInclude<TestType, number>, { b: number }>>,
	Expect<Equal<FilterInclude<TestType, boolean>, { c: boolean }>>,
	Expect<Equal<FilterInclude<TestType, unknown>, TestType>>
];

type TestTypeNever = {
	a: string;
	b: number;
	c: boolean;
	d: never;
};

type asserts_NeverKeys = [
	Expect<Equal<NonNeverKeys<TestType>, 'a' | 'b' | 'c'>>,
	Expect<Equal<NonNeverKeys<TestTypeNever>, 'a' | 'b' | 'c'>>
];

type asserts_OmitNever = [
	Expect<Equal<OmitNever<TestType>, TestType>>,
	Expect<Equal<OmitNever<TestTypeNever>, { a: string; b: number; c: boolean }>>
];

type TestTypeDeep = {
	a: string;
	b: number;
	c: boolean;
	d: {
		e: string;
		f: number;
		g: boolean;
	};
	h: {
		i: string;
		j: number;
		k: boolean;
	}[];
};

type asserts_DeepFilter = [
	Expect<
		Equal<DeepFilter<TestTypeDeep, string>, { a: string; d: { e: string }; h: { i: string }[] }>
	>,
	Expect<
		Equal<DeepFilter<TestTypeDeep, number>, { b: number; d: { f: number }; h: { j: number }[] }>
	>,
	Expect<
		Equal<DeepFilter<TestTypeDeep, boolean>, { c: boolean; d: { g: boolean }; h: { k: boolean }[] }>
	>,
	Expect<
		Equal<
			DeepFilter<TestTypeDeep, string | number>,
			{ a: string; b: number; d: { e: string; f: number }; h: { i: string; j: number }[] }
		>
	>,
	Expect<Equal<DeepFilter<TestTypeDeep, unknown>, TestTypeDeep>>
];