├── .npmrc ├── .gitattributes ├── .gitignore ├── source ├── opaque.d.ts ├── primitive.d.ts ├── internal │ ├── index.d.ts │ └── characters.d.ts ├── typed-array.d.ts ├── is-null.d.ts ├── non-empty-tuple.d.ts ├── less-than.d.ts ├── stringified.d.ts ├── less-than-or-equal.d.ts ├── if-any.d.ts ├── greater-than-or-equal.d.ts ├── if-null.d.ts ├── unknown-array.d.ts ├── if-never.d.ts ├── and.d.ts ├── or.d.ts ├── string-key-of.d.ts ├── if-unknown.d.ts ├── includes.d.ts ├── trim.d.ts ├── if-empty-object.d.ts ├── array-values.d.ts ├── arrayable.d.ts ├── has-optional-keys.d.ts ├── has-readonly-keys.d.ts ├── has-writable-keys.d.ts ├── readonly-keys-of.d.ts ├── unknown-record.d.ts ├── global-this.d.ts ├── snake-cased-properties.d.ts ├── kebab-cased-properties.d.ts ├── single-key-object.d.ts ├── async-return-type.d.ts ├── writable-keys-of.d.ts ├── array-tail.d.ts ├── split.d.ts ├── array-indices.d.ts ├── is-float.d.ts ├── promisable.d.ts ├── string-slice.d.ts ├── keys-of-union.d.ts ├── snake-case.d.ts ├── kebab-case.d.ts ├── delimiter-cased-properties.d.ts ├── pascal-case.d.ts ├── camel-cased-properties.d.ts ├── pascal-cased-properties.d.ts ├── is-any.d.ts ├── require-at-least-one.d.ts ├── value-of.d.ts ├── required-keys-of.d.ts ├── literal-to-primitive.d.ts ├── optional-keys-of.d.ts ├── require-one-or-none.d.ts ├── screaming-snake-case.d.ts ├── snake-cased-properties-deep.d.ts ├── non-empty-object.d.ts ├── kebab-cased-properties-deep.d.ts ├── is-equal.d.ts ├── string-repeat.d.ts ├── conditional-pick.d.ts ├── jsonifiable.d.ts ├── is-never.d.ts ├── conditional-except.d.ts ├── set-non-nullable.d.ts ├── is-integer.d.ts ├── require-exactly-one.d.ts ├── enforce-optional.d.ts ├── literal-to-primitive-deep.d.ts ├── merge.d.ts ├── set-optional.d.ts ├── asyncify.d.ts ├── set-readonly.d.ts ├── override-properties.d.ts ├── literal-union.d.ts ├── conditional-simplify.d.ts ├── int-closed-range.d.ts ├── require-all-or-none.d.ts ├── has-required-keys.d.ts ├── pascal-cased-properties-deep.d.ts ├── tagged-union.d.ts ├── conditional-keys.d.ts ├── last-array-element.d.ts ├── set-required-deep.d.ts ├── union-to-tuple.d.ts ├── merge-exclusive.d.ts ├── multidimensional-array.d.ts ├── set-required.d.ts ├── is-unknown.d.ts ├── set-return-type.d.ts ├── greater-than.d.ts ├── empty-object.d.ts ├── multidimensional-readonly-array.d.ts ├── readonly-tuple.d.ts ├── replace.d.ts ├── fixed-length-array.d.ts └── set-field-type.d.ts ├── media ├── logo.png ├── logo.sketch ├── logo@2x.png └── readme.md ├── .github ├── funding.yml ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── 3 enhancement.md │ ├── 1 new type.yml │ └── 2 bug report.yml ├── security.md ├── pull_request_template.md ├── dependabot.yml └── workflows │ ├── ts-canary.yml │ └── main.yml ├── test-d ├── promisable.ts ├── internal │ ├── not.ts │ ├── build-tuple.ts │ ├── is-number-like.ts │ ├── is-whitespace.ts │ ├── tuple-max.ts │ ├── number-absolute.ts │ ├── is-not-false.ts │ ├── tuple-min.ts │ ├── require-none.ts │ ├── object-value.ts │ ├── is-union.ts │ ├── has-multiple-call-signatures.ts │ └── is-numeric.ts ├── string-key-of.ts ├── ts41.ts ├── non-empty-tuple.ts ├── or.ts ├── if-never.ts ├── and.ts ├── trim.ts ├── if-any.ts ├── if-unknown.ts ├── pascal-case.ts ├── value-of.ts ├── is-null.ts ├── stringified.ts ├── async-return-type.ts ├── enforce-optional.ts ├── snake-cased-properties.ts ├── kebab-cased-properties.ts ├── fixed-length-array.ts ├── literal-to-primitive.ts ├── unknown-record.ts ├── global-this.ts ├── union-to-tuple.ts ├── kebab-case.ts ├── single-key-object.ts ├── string-slice.ts ├── readonly-tuple.ts ├── is-never.ts ├── conditional-keys.ts ├── tagged-union.ts ├── is-unknown.ts ├── optional-keys-of.ts ├── required-keys-of.ts ├── has-optional-keys.ts ├── has-required-keys.ts ├── readonly-keys-of.ts ├── writable-keys-of.ts ├── snake-case.ts ├── has-readonly-keys.ts ├── has-writable-keys.ts ├── non-empty-object.ts ├── pascal-cased-properties.ts ├── pick-index-signature.ts ├── int-closed-range.ts ├── union-to-intersection.ts ├── array-indices.ts ├── delimiter-cased-properties.ts ├── is-float.ts ├── is-integer.ts ├── tsconfig-json.ts ├── int-range.ts ├── require-exactly-one.ts ├── except.ts ├── merge-exclusive.ts ├── conditional-pick.ts ├── observable-like.ts ├── string-repeat.ts ├── multidimensional-array.ts ├── keys-of-union.ts ├── require-all-or-none.ts ├── is-any.ts ├── split.ts ├── sum.ts ├── asyncify.ts ├── conditional-except.ts ├── empty-object.ts ├── invariant-of.ts ├── simplify-deep.ts ├── arrayable.ts ├── override-properties.ts ├── replace.ts ├── less-than.ts ├── literal-to-primitive-deep.ts ├── screaming-snake-case.ts ├── camel-cased-properties.ts ├── greater-than.ts ├── jsonifiable.ts ├── multidimensional-readonly-array.ts ├── omit-index-signature.ts ├── snake-cased-properties-deep.ts ├── less-than-or-equal.ts ├── require-one-or-none.ts ├── last-array-element.ts ├── kebab-cased-properties-deep.ts ├── tuple-to-union.ts ├── subtract.ts ├── greater-than-or-equal.ts ├── array-values.ts ├── require-at-least-one.ts ├── array-tail.ts ├── pascal-cased-properties-deep.ts ├── array-splice.ts ├── unknown-array.ts ├── iterable-element.ts ├── is-equal.ts ├── set-non-nullable.ts ├── set-return-type.ts └── entries.ts ├── .editorconfig ├── script └── test │ └── source-files-extension.js ├── tsconfig.json └── license-mit /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | -------------------------------------------------------------------------------- /source/opaque.d.ts: -------------------------------------------------------------------------------- 1 | export * from './tagged'; 2 | -------------------------------------------------------------------------------- /media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ytonali/type-fest/HEAD/media/logo.png -------------------------------------------------------------------------------- /media/logo.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ytonali/type-fest/HEAD/media/logo.sketch -------------------------------------------------------------------------------- /media/logo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ytonali/type-fest/HEAD/media/logo@2x.png -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | github: [sindresorhus, voxpelli, skarab42, Emiyaaaaa] 2 | tidelift: npm/type-fest 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # @voxpelli contributed the casing helpers and thus knows a lot about them 2 | *case*.ts @voxpelli 3 | -------------------------------------------------------------------------------- /media/readme.md: -------------------------------------------------------------------------------- 1 | # Media 2 | 3 | ## Attribution 4 | 5 | ### Fireworks vector graphic 6 | 7 | [Free Vectors via Vecteezy!](https://www.vecteezy.com) 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3 enhancement.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ♻️ Propose change or improvement to existing types 3 | about: '​‌‍⁠ ' # Magic whitespace to hide this required field 4 | labels: 'enhancement' 5 | --- 6 | -------------------------------------------------------------------------------- /.github/security.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. 4 | -------------------------------------------------------------------------------- /test-d/promisable.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Promisable} from '../index'; 3 | 4 | declare const promisable: Promisable; 5 | expectType | string>(promisable); 6 | -------------------------------------------------------------------------------- /test-d/internal/not.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Not} from '../../source/internal'; 3 | 4 | expectType>(false); 5 | expectType>(true); 6 | // FIXME 7 | expectType>(null! as boolean); 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /test-d/string-key-of.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {StringKeyOf} from '../index'; 3 | 4 | declare const foo: StringKeyOf<{ 5 | 1: number; 6 | stringKey: string; 7 | }>; 8 | 9 | expectType<'1' | 'stringKey'>(foo); 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /test-d/ts41.ts: -------------------------------------------------------------------------------- 1 | // Ensure that TypeScript 4.1 types are available. 2 | import {expectType} from 'tsd'; 3 | import type {CamelCase} from '../index'; 4 | 5 | const camelFromPascal: CamelCase<'FooBar'> = 'fooBar'; 6 | expectType>(camelFromPascal); 7 | -------------------------------------------------------------------------------- /test-d/internal/build-tuple.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {BuildTuple} from '../../source/internal'; 3 | 4 | expectType>([null, null, null]); 5 | expectType>([0, 0, 0, 0, 0]); 6 | expectType>([]); 7 | -------------------------------------------------------------------------------- /source/primitive.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive). 3 | 4 | @category Type 5 | */ 6 | export type Primitive = 7 | | null 8 | | undefined 9 | | string 10 | | number 11 | | boolean 12 | | symbol 13 | | bigint; 14 | -------------------------------------------------------------------------------- /source/internal/index.d.ts: -------------------------------------------------------------------------------- 1 | export type * from './array'; 2 | export type * from './characters'; 3 | export type * from './keys'; 4 | export type * from './numeric'; 5 | export type * from './object'; 6 | export type * from './string'; 7 | export type * from './tuple'; 8 | export type * from './type'; 9 | -------------------------------------------------------------------------------- /test-d/non-empty-tuple.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {NonEmptyTuple} from '../index'; 3 | 4 | declare const sum: (...numbers: NonEmptyTuple) => number; 5 | 6 | expectType(sum(1, 2, 3)); 7 | expectType(sum(1)); 8 | 9 | // @ts-expect-error 10 | sum(); 11 | -------------------------------------------------------------------------------- /test-d/internal/is-number-like.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsNumberLike} from '../../source/internal/numeric.d'; 3 | 4 | expectType>(true); 5 | expectType>(true); 6 | expectType>(true); 7 | expectType>(true); 8 | expectType>(false); 9 | -------------------------------------------------------------------------------- /test-d/or.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Or} from '../source/or'; 3 | 4 | declare const never: never; 5 | 6 | expectType>(true); 7 | expectType>(true); 8 | expectType>(true); 9 | expectType>(false); 10 | expectType>(true); 11 | expectType>(never); 12 | expectType>(never); 13 | -------------------------------------------------------------------------------- /test-d/if-never.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IfNever} from '../index'; 3 | 4 | // `IfNever` should return `true`/`false` if only `T` is specified 5 | expectType>(true); 6 | expectType>(false); 7 | expectType>('T'); 8 | expectType>('F'); 9 | 10 | // Missing generic parameter 11 | // @ts-expect-error 12 | type A = IfNever; 13 | -------------------------------------------------------------------------------- /test-d/and.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {And} from '../source/and'; 3 | 4 | declare const never: never; 5 | 6 | expectType>(true); 7 | expectType>(false); 8 | expectType>(false); 9 | expectType>(false); 10 | expectType>(never); 11 | expectType>(false); 12 | expectType>(never); 13 | -------------------------------------------------------------------------------- /test-d/trim.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Trim} from '../index'; 3 | 4 | declare function trim(value: S): Trim; 5 | 6 | expectType<'foo'>(trim(' foo')); 7 | expectType<'bar'>(trim('bar ')); 8 | expectType<'baz'>(trim(' baz ')); 9 | expectType<'waldo'>(trim(' waldo ')); 10 | expectType<'fr ed'>(trim(' fr ed ')); 11 | expectType<'foo'>(trim(' foo\n')); 12 | expectType<'foo'>(trim(' foo\n\t ')); 13 | -------------------------------------------------------------------------------- /test-d/if-any.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IfAny} from '../index'; 3 | 4 | declare const _any: any; 5 | 6 | // `IfAny` should return `true`/`false` if only `T` is specified 7 | expectType>(true); 8 | expectType>(false); 9 | expectType>('T'); 10 | expectType>('F'); 11 | 12 | // Missing generic parameter 13 | // @ts-expect-error 14 | type A = IfAny; 15 | -------------------------------------------------------------------------------- /test-d/if-unknown.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IfUnknown} from '../index'; 3 | 4 | // `IfUnknown` should return `true`/`false` if only `T` is specified 5 | expectType>(true); 6 | expectType>(false); 7 | expectType>('T'); 8 | expectType>('F'); 9 | 10 | // Missing generic parameter 11 | // @ts-expect-error 12 | type A = IfUnknown; 13 | -------------------------------------------------------------------------------- /test-d/pascal-case.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {PascalCase} from '../index'; 3 | 4 | const pascalFromCamel: PascalCase<'fooBar'> = 'FooBar'; 5 | expectType<'FooBar'>(pascalFromCamel); 6 | 7 | const pascalFromKebab: PascalCase<'foo-bar'> = 'FooBar'; 8 | expectType<'FooBar'>(pascalFromKebab); 9 | 10 | const pascalFromComplexKebab: PascalCase<'foo-bar-abc-123'> = 'FooBarAbc123'; 11 | expectType<'FooBarAbc123'>(pascalFromComplexKebab); 12 | -------------------------------------------------------------------------------- /test-d/value-of.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable, expectType} from 'tsd'; 2 | import type {ValueOf} from '../index'; 3 | 4 | const value: ValueOf<{a: 1; b: 2; c: 3}> = 3; 5 | const valueRestricted: ValueOf<{a: 1; b: 2; c: 3}, 'a'> = 1; 6 | 7 | expectAssignable<1 | 2 | 3>(value); 8 | expectNotAssignable<4>(value); 9 | 10 | expectType<1>(valueRestricted); 11 | expectNotAssignable<2>(valueRestricted); 12 | expectNotAssignable<4>(valueRestricted); 13 | -------------------------------------------------------------------------------- /test-d/internal/is-whitespace.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsWhitespace} from '../../source/internal'; 3 | 4 | expectType>(false); 5 | expectType>(true); 6 | expectType>(true); 7 | expectType>(true); 8 | expectType>(false); 9 | expectType>(false); 10 | expectType>(true); 11 | expectType>(true); 12 | -------------------------------------------------------------------------------- /test-d/internal/tuple-max.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {TupleMax} from '../../source/internal'; 3 | import type {PositiveInfinity} from '../../source/numeric'; 4 | 5 | expectType>(7); 6 | expectType>(null! as PositiveInfinity); 7 | expectType>(1); 8 | expectType>(-1); 9 | expectType>(10); 10 | -------------------------------------------------------------------------------- /source/typed-array.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Matches any [typed array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), like `Uint8Array` or `Float64Array`. 3 | 4 | @category Array 5 | */ 6 | export type TypedArray = 7 | | Int8Array 8 | | Uint8Array 9 | | Uint8ClampedArray 10 | | Int16Array 11 | | Uint16Array 12 | | Int32Array 13 | | Uint32Array 14 | | Float32Array 15 | | Float64Array 16 | | BigInt64Array 17 | | BigUint64Array; 18 | -------------------------------------------------------------------------------- /test-d/is-null.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsNull} from '../source/is-null'; 3 | 4 | // https://www.typescriptlang.org/docs/handbook/type-compatibility.html 5 | expectType>(true); 6 | expectType>(true); 7 | expectType>(true); 8 | expectType>(false); // Depends on `strictNullChecks` 9 | expectType>(false); 10 | expectType>(false); 11 | expectType>(false); 12 | -------------------------------------------------------------------------------- /test-d/stringified.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable, expectType} from 'tsd'; 2 | import type {Stringified} from '../index'; 3 | 4 | declare const stringified: Stringified<{a: number; b: string}>; 5 | expectType<{a: string; b: string}>(stringified); 6 | 7 | type Car = { 8 | model: string; 9 | speed: number; 10 | }; 11 | expectNotAssignable>({model: 'Foo', speed: 101}); 12 | expectAssignable>({model: 'Foo', speed: '101'}); 13 | -------------------------------------------------------------------------------- /test-d/async-return-type.ts: -------------------------------------------------------------------------------- 1 | import {expectNotAssignable, expectType} from 'tsd'; 2 | import type {AsyncReturnType} from '../index'; 3 | 4 | async function asyncFunction(): Promise { 5 | return 2; 6 | } 7 | 8 | type Value = AsyncReturnType; 9 | 10 | asyncFunction().then(value => { // eslint-disable-line unicorn/prefer-top-level-await, @typescript-eslint/no-floating-promises 11 | expectType(value); 12 | expectNotAssignable(value); 13 | }); 14 | -------------------------------------------------------------------------------- /test-d/enforce-optional.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {EnforceOptional} from '../source/enforce-optional'; 3 | 4 | type Foo = { 5 | a: string; 6 | b?: string; 7 | c: undefined; 8 | d: number | undefined; 9 | }; 10 | 11 | type EnforcedOptionalFoo = EnforceOptional; 12 | 13 | declare const enforcedOptionalFoo: EnforcedOptionalFoo; 14 | 15 | expectType<{ 16 | a: string; 17 | b?: string; 18 | c: undefined; 19 | d?: number; 20 | }>(enforcedOptionalFoo); 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'github-actions' 4 | directory: '/' 5 | schedule: 6 | interval: 'weekly' 7 | groups: 8 | github-actions: 9 | patterns: 10 | - '*' 11 | - package-ecosystem: 'npm' 12 | directory: '/' 13 | schedule: 14 | interval: 'monthly' 15 | versioning-strategy: 'increase-if-necessary' 16 | groups: 17 | development-dependencies: 18 | dependency-type: 'development' 19 | -------------------------------------------------------------------------------- /test-d/snake-cased-properties.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {SnakeCasedProperties} from '../index'; 3 | 4 | declare const foo: SnakeCasedProperties<{helloWorld: {fooBar: string}}>; 5 | expectType<{hello_world: {fooBar: string}}>(foo); 6 | 7 | // Verify example 8 | type User = { 9 | userId: number; 10 | userName: string; 11 | }; 12 | const result: SnakeCasedProperties = { 13 | user_id: 1, 14 | user_name: 'Tom', 15 | }; 16 | expectType>(result); 17 | -------------------------------------------------------------------------------- /test-d/kebab-cased-properties.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {KebabCasedProperties} from '../index'; 3 | 4 | declare const foo: KebabCasedProperties<{helloWorld: {fooBar: string}}>; 5 | expectType<{'hello-world': {fooBar: string}}>(foo); 6 | 7 | // Verify example 8 | type User = { 9 | userId: number; 10 | userName: string; 11 | }; 12 | const result: KebabCasedProperties = { 13 | 'user-id': 1, 14 | 'user-name': 'Tom', 15 | }; 16 | expectType>(result); 17 | -------------------------------------------------------------------------------- /test-d/fixed-length-array.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable} from 'tsd'; 2 | import type {FixedLengthArray} from '../index'; 3 | 4 | type FixedToThreeStrings = FixedLengthArray; 5 | 6 | expectAssignable(['a', 'b', 'c']); 7 | 8 | expectNotAssignable(['a', 'b', 123]); 9 | expectNotAssignable(['a']); 10 | expectNotAssignable(['a', 'b']); 11 | expectNotAssignable(['a', 'b', 'c', 'd']); 12 | -------------------------------------------------------------------------------- /source/is-null.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Returns a boolean for whether the given type is `null`. 3 | 4 | @example 5 | ``` 6 | import type {IsNull} from 'type-fest'; 7 | 8 | type NonNullFallback = IsNull extends true ? Fallback : T; 9 | 10 | type Example1 = NonNullFallback; 11 | //=> string 12 | 13 | type Example2 = NonNullFallback; 14 | //=? number 15 | ``` 16 | 17 | @category Type Guard 18 | @category Utilities 19 | */ 20 | export type IsNull = [T] extends [null] ? true : false; 21 | -------------------------------------------------------------------------------- /test-d/internal/number-absolute.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {NumberAbsolute} from '../../source/internal'; 3 | import type {NegativeInfinity, PositiveInfinity} from '../../source/numeric'; 4 | 5 | expectType>(3); 6 | expectType>(3); 7 | expectType>(0); 8 | expectType>(0); 9 | expectType>(null! as PositiveInfinity); 10 | expectType>(null! as PositiveInfinity); 11 | -------------------------------------------------------------------------------- /test-d/literal-to-primitive.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {LiteralToPrimitive} from '../index'; 3 | 4 | // Simple usage 5 | declare const numberPrimitive: LiteralToPrimitive<123>; 6 | expectType(numberPrimitive); 7 | 8 | const symbol = Symbol('foo'); 9 | 10 | // Union 11 | declare const kitchenSink: LiteralToPrimitive<123 | 123n | 'hello' | true | undefined | typeof symbol | null | {key: string}>; 12 | expectType(kitchenSink); 13 | -------------------------------------------------------------------------------- /source/non-empty-tuple.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Matches any non-empty tuple. 3 | 4 | @example 5 | ``` 6 | import type {NonEmptyTuple} from 'type-fest'; 7 | 8 | const sum = (...numbers: NonEmptyTuple) => numbers.reduce((total, value) => total + value, 0); 9 | 10 | sum(1, 2, 3); 11 | //=> 6 12 | 13 | sum(); 14 | //=> Error: Expected at least 1 arguments, but got 0. 15 | ``` 16 | 17 | @see {@link RequireAtLeastOne} for objects 18 | 19 | @category Array 20 | */ 21 | export type NonEmptyTuple = readonly [T, ...T[]]; 22 | -------------------------------------------------------------------------------- /source/less-than.d.ts: -------------------------------------------------------------------------------- 1 | import type {GreaterThanOrEqual} from './greater-than-or-equal'; 2 | 3 | /** 4 | Returns a boolean for whether a given number is less than another number. 5 | 6 | @example 7 | ``` 8 | import type {LessThan} from 'type-fest'; 9 | 10 | LessThan<1, -5>; 11 | //=> false 12 | 13 | LessThan<1, 1>; 14 | //=> false 15 | 16 | LessThan<1, 5>; 17 | //=> true 18 | ``` 19 | */ 20 | export type LessThan = number extends A | B 21 | ? never 22 | : GreaterThanOrEqual extends true ? false : true; 23 | -------------------------------------------------------------------------------- /test-d/unknown-record.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectType} from 'tsd'; 2 | import type {UnknownRecord} from '../index'; 3 | 4 | declare let foo: UnknownRecord; 5 | 6 | expectAssignable(foo); 7 | expectAssignable(foo = {}); 8 | expectAssignable(foo = {bar: 'baz'}); 9 | expectAssignable(foo = {bar: {baz: 'hello'}}); 10 | 11 | // @ts-expect-error 12 | foo = []; 13 | // @ts-expect-error 14 | foo = 42; 15 | // @ts-expect-error 16 | foo = null; 17 | 18 | expectType(foo['bar']); 19 | -------------------------------------------------------------------------------- /test-d/internal/is-not-false.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-duplicate-type-constituents */ 2 | import {expectType} from 'tsd'; 3 | import type {IsNotFalse} from '../../source/internal'; 4 | 5 | expectType>(true); 6 | expectType>(true); 7 | expectType>(true); 8 | expectType>(true); 9 | expectType>(false); 10 | expectType>(false); 11 | expectType>(false); 12 | -------------------------------------------------------------------------------- /source/stringified.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Create a type with the keys of the given type changed to `string` type. 3 | 4 | Use-case: Changing interface values to strings in order to use them in a form model. 5 | 6 | @example 7 | ``` 8 | import type {Stringified} from 'type-fest'; 9 | 10 | type Car = { 11 | model: string; 12 | speed: number; 13 | } 14 | 15 | const carForm: Stringified = { 16 | model: 'Foo', 17 | speed: '101' 18 | }; 19 | ``` 20 | 21 | @category Object 22 | */ 23 | export type Stringified = {[KeyType in keyof ObjectType]: string}; 24 | -------------------------------------------------------------------------------- /test-d/internal/tuple-min.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {TupleMin} from '../../source/internal'; 3 | import type {NegativeInfinity, PositiveInfinity} from '../../source/numeric'; 4 | 5 | declare const never: never; 6 | 7 | expectType>(-9); 8 | expectType>(null! as NegativeInfinity); 9 | expectType>(1); 10 | expectType>(-5); 11 | expectType>(never); 12 | -------------------------------------------------------------------------------- /source/less-than-or-equal.d.ts: -------------------------------------------------------------------------------- 1 | import type {GreaterThan} from './greater-than'; 2 | 3 | /** 4 | Returns a boolean for whether a given number is less than or equal to another number. 5 | 6 | @example 7 | ``` 8 | import type {LessThanOrEqual} from 'type-fest'; 9 | 10 | LessThanOrEqual<1, -5>; 11 | //=> false 12 | 13 | LessThanOrEqual<1, 1>; 14 | //=> true 15 | 16 | LessThanOrEqual<1, 5>; 17 | //=> true 18 | ``` 19 | */ 20 | export type LessThanOrEqual = number extends A | B 21 | ? never 22 | : GreaterThan extends true ? false : true; 23 | -------------------------------------------------------------------------------- /source/if-any.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsAny} from './is-any'; 2 | 3 | /** 4 | An if-else-like type that resolves depending on whether the given type is `any`. 5 | 6 | @see {@link IsAny} 7 | 8 | @example 9 | ``` 10 | import type {IfAny} from 'type-fest'; 11 | 12 | type ShouldBeTrue = IfAny; 13 | //=> true 14 | 15 | type ShouldBeBar = IfAny<'not any', 'foo', 'bar'>; 16 | //=> 'bar' 17 | ``` 18 | 19 | @category Type Guard 20 | @category Utilities 21 | */ 22 | export type IfAny = ( 23 | IsAny extends true ? TypeIfAny : TypeIfNotAny 24 | ); 25 | -------------------------------------------------------------------------------- /source/greater-than-or-equal.d.ts: -------------------------------------------------------------------------------- 1 | import type {GreaterThan} from './greater-than'; 2 | 3 | /** 4 | Returns a boolean for whether a given number is greater than or equal to another number. 5 | 6 | @example 7 | ``` 8 | import type {GreaterThanOrEqual} from 'type-fest'; 9 | 10 | GreaterThanOrEqual<1, -5>; 11 | //=> true 12 | 13 | GreaterThanOrEqual<1, 1>; 14 | //=> true 15 | 16 | GreaterThanOrEqual<1, 5>; 17 | //=> false 18 | ``` 19 | */ 20 | export type GreaterThanOrEqual = number extends A | B 21 | ? never 22 | : A extends B ? true : GreaterThan; 23 | -------------------------------------------------------------------------------- /source/if-null.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsNull} from './is-null'; 2 | 3 | /** 4 | An if-else-like type that resolves depending on whether the given type is `null`. 5 | 6 | @see {@link IsNull} 7 | 8 | @example 9 | ``` 10 | import type {IfNull} from 'type-fest'; 11 | 12 | type ShouldBeTrue = IfNull; 13 | //=> true 14 | 15 | type ShouldBeBar = IfNull<'not null', 'foo', 'bar'>; 16 | //=> 'bar' 17 | ``` 18 | 19 | @category Type Guard 20 | @category Utilities 21 | */ 22 | export type IfNull = ( 23 | IsNull extends true ? TypeIfNull : TypeIfNotNull 24 | ); 25 | -------------------------------------------------------------------------------- /source/unknown-array.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Represents an array with `unknown` value. 3 | 4 | Use case: You want a type that all arrays can be assigned to, but you don't care about the value. 5 | 6 | @example 7 | ``` 8 | import type {UnknownArray} from 'type-fest'; 9 | 10 | type IsArray = T extends UnknownArray ? true : false; 11 | 12 | type A = IsArray<['foo']>; 13 | //=> true 14 | 15 | type B = IsArray; 16 | //=> true 17 | 18 | type C = IsArray; 19 | //=> false 20 | ``` 21 | 22 | @category Type 23 | @category Array 24 | */ 25 | export type UnknownArray = readonly unknown[]; 26 | -------------------------------------------------------------------------------- /test-d/global-this.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {GlobalThis} from '../index'; 3 | 4 | type ExtraProperties = GlobalThis & { 5 | readonly GLOBAL_TOKEN: string; 6 | }; 7 | 8 | // Verify `globalThis` can be cast to a type which extends `GlobalThis`. 9 | expectType((globalThis as ExtraProperties).GLOBAL_TOKEN); 10 | 11 | // Verify that object literals cannot be cast to a type which extends `GlobalThis`. 12 | declare function consumeExtraProperties(extraProperties: ExtraProperties): void; 13 | // @ts-expect-error 14 | consumeExtraProperties(({something: 'value'}) as ExtraProperties); 15 | -------------------------------------------------------------------------------- /source/if-never.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsNever} from './is-never'; 2 | 3 | /** 4 | An if-else-like type that resolves depending on whether the given type is `never`. 5 | 6 | @see {@link IsNever} 7 | 8 | @example 9 | ``` 10 | import type {IfNever} from 'type-fest'; 11 | 12 | type ShouldBeTrue = IfNever; 13 | //=> true 14 | 15 | type ShouldBeBar = IfNever<'not never', 'foo', 'bar'>; 16 | //=> 'bar' 17 | ``` 18 | 19 | @category Type Guard 20 | @category Utilities 21 | */ 22 | export type IfNever = ( 23 | IsNever extends true ? TypeIfNever : TypeIfNotNever 24 | ); 25 | -------------------------------------------------------------------------------- /source/and.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsEqual} from './is-equal'; 2 | 3 | /** 4 | Returns a boolean for whether two given types are both true. 5 | 6 | Use-case: Constructing complex conditional types where multiple conditions must be satisfied. 7 | 8 | @example 9 | ``` 10 | import type {And} from 'type-fest'; 11 | 12 | And; 13 | //=> true 14 | 15 | And; 16 | //=> false 17 | ``` 18 | 19 | @see {@link Or} 20 | */ 21 | export type And = [A, B][number] extends true 22 | ? true 23 | : true extends [IsEqual, IsEqual][number] 24 | ? false 25 | : never; 26 | -------------------------------------------------------------------------------- /source/or.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsEqual} from './is-equal'; 2 | 3 | /** 4 | Returns a boolean for whether either of two given types are true. 5 | 6 | Use-case: Constructing complex conditional types where multiple conditions must be satisfied. 7 | 8 | @example 9 | ``` 10 | import type {Or} from 'type-fest'; 11 | 12 | Or; 13 | //=> true 14 | 15 | Or; 16 | //=> false 17 | ``` 18 | 19 | @see {@link And} 20 | */ 21 | export type Or = [A, B][number] extends false 22 | ? false 23 | : true extends [IsEqual, IsEqual][number] 24 | ? true 25 | : never; 26 | -------------------------------------------------------------------------------- /test-d/union-to-tuple.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectError, expectType} from 'tsd'; 2 | import type {UnionToTuple} from '../index'; 3 | 4 | type Options = UnionToTuple<'a' | 'b' | 'c'>; 5 | // Results unordered 6 | expectAssignable<['a', 'b', 'c'] | ['a', 'c', 'b'] | ['b', 'a', 'c'] | ['b', 'c', 'a'] | ['c', 'a', 'b'] | ['c', 'b', 'a']>({} as Options); 7 | expectType({} as ('a' | 'b' | 'c')); 8 | 9 | type Options1 = UnionToTuple<1 | 2 | 3>; 10 | expectType({} as (1 | 2 | 3)); 11 | 12 | type Options2 = UnionToTuple; 13 | expectType({} as (1 | false | true)); 14 | -------------------------------------------------------------------------------- /source/string-key-of.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Get keys of the given type as strings. 3 | 4 | Number keys are converted to strings. 5 | 6 | Use-cases: 7 | - Get string keys from a type which may have number keys. 8 | - Makes it possible to index using strings retrieved from template types. 9 | 10 | @example 11 | ``` 12 | import type {StringKeyOf} from 'type-fest'; 13 | 14 | type Foo = { 15 | 1: number, 16 | stringKey: string, 17 | }; 18 | 19 | type StringKeysOfFoo = StringKeyOf; 20 | //=> '1' | 'stringKey' 21 | ``` 22 | 23 | @category Object 24 | */ 25 | export type StringKeyOf = `${Extract}`; 26 | -------------------------------------------------------------------------------- /test-d/kebab-case.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {KebabCase} from '../index'; 3 | 4 | const kebabFromCamel: KebabCase<'fooBar'> = 'foo-bar'; 5 | expectType<'foo-bar'>(kebabFromCamel); 6 | 7 | const kebabFromKebab: KebabCase<'foo-bar'> = 'foo-bar'; 8 | expectType<'foo-bar'>(kebabFromKebab); 9 | 10 | const kebabFromSpace: KebabCase<'foo bar'> = 'foo-bar'; 11 | expectType<'foo-bar'>(kebabFromSpace); 12 | 13 | const kebabFromSnake: KebabCase<'foo_bar'> = 'foo-bar'; 14 | expectType<'foo-bar'>(kebabFromSnake); 15 | 16 | const noKebabFromMono: KebabCase<'foobar'> = 'foobar'; 17 | expectType<'foobar'>(noKebabFromMono); 18 | -------------------------------------------------------------------------------- /test-d/single-key-object.ts: -------------------------------------------------------------------------------- 1 | import {expectNever, expectAssignable} from 'tsd'; 2 | import type {SingleKeyObject} from '../index'; 3 | 4 | const test = (_: SingleKeyObject): void => {}; // eslint-disable-line @typescript-eslint/no-empty-function 5 | 6 | test({key: 'value'}); 7 | 8 | // @ts-expect-error 9 | test({}); 10 | // @ts-expect-error 11 | test({key: 'value', otherKey: 'other value'}); 12 | 13 | declare const validObject: SingleKeyObject<{key: string}>; 14 | expectAssignable<{key: string}>(validObject); 15 | 16 | declare const invalidObject: SingleKeyObject<{key1: string; key2: number}>; 17 | expectNever(invalidObject); 18 | -------------------------------------------------------------------------------- /source/if-unknown.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsUnknown} from './is-unknown'; 2 | 3 | /** 4 | An if-else-like type that resolves depending on whether the given type is `unknown`. 5 | 6 | @see {@link IsUnknown} 7 | 8 | @example 9 | ``` 10 | import type {IfUnknown} from 'type-fest'; 11 | 12 | type ShouldBeTrue = IfUnknown; 13 | //=> true 14 | 15 | type ShouldBeBar = IfUnknown<'not unknown', 'foo', 'bar'>; 16 | //=> 'bar' 17 | ``` 18 | 19 | @category Type Guard 20 | @category Utilities 21 | */ 22 | export type IfUnknown = ( 23 | IsUnknown extends true ? TypeIfUnknown : TypeIfNotUnknown 24 | ); 25 | -------------------------------------------------------------------------------- /test-d/internal/require-none.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable} from 'tsd'; 2 | import type {RequireNone} from '../../source/internal'; 3 | 4 | type NoneAllowed = RequireNone<'foo' | 'bar'>; 5 | 6 | expectAssignable({}); 7 | expectNotAssignable({foo: 'foo'}); 8 | expectNotAssignable({bar: 'bar'}); 9 | expectNotAssignable({foo: 'foo', bar: 'bar'}); 10 | 11 | type SomeAllowed = Record<'bar', string> & RequireNone<'foo'>; 12 | 13 | expectAssignable({bar: 'bar'}); 14 | expectNotAssignable({foo: 'foo'}); 15 | expectNotAssignable({foo: 'foo', bar: 'bar'}); 16 | -------------------------------------------------------------------------------- /test-d/string-slice.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {StringSlice} from '../index'; 3 | 4 | expectType>('abcde'); 5 | expectType>('abcde'); 6 | expectType>('abcd'); 7 | expectType>('bcd'); 8 | expectType>('b'); 9 | expectType>('bc'); 10 | expectType>('abcd'); 11 | expectType>('ab'); 12 | expectType>('de'); 13 | expectType>(''); 14 | expectType>(''); 15 | -------------------------------------------------------------------------------- /test-d/internal/object-value.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {ObjectValue} from '../../source/internal'; 3 | 4 | type ObjectT = { 5 | string: string; 6 | 0: number; 7 | '1': number; 8 | }; 9 | 10 | declare const normal: ObjectValue; 11 | expectType(normal); 12 | 13 | declare const test0: ObjectValue; 14 | expectType(test0); 15 | declare const teststring0: ObjectValue; 16 | expectType(teststring0); 17 | declare const test1: ObjectValue; 18 | expectType(test1); 19 | declare const teststring1: ObjectValue; 20 | expectType(teststring1); 21 | -------------------------------------------------------------------------------- /test-d/readonly-tuple.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable} from 'tsd'; 2 | import type {ReadonlyTuple} from '../index'; 3 | 4 | type TupleOfThreeStrings = ReadonlyTuple; 5 | 6 | expectAssignable(['a', 'b', 'c']); 7 | 8 | expectNotAssignable(['a', 'b', 123]); 9 | expectNotAssignable(['a']); 10 | expectNotAssignable(['a', 'b']); 11 | expectNotAssignable(['a', 'b', 'c', 'd']); 12 | 13 | declare const test: TupleOfThreeStrings; 14 | 15 | // @ts-expect-error 16 | const _a: unknown = test.push; 17 | // @ts-expect-error 18 | test[2] = 'a'; 19 | -------------------------------------------------------------------------------- /source/includes.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsEqual} from './is-equal'; 2 | 3 | /** 4 | Returns a boolean for whether the given array includes the given item. 5 | 6 | This can be useful if another type wants to make a decision based on whether the array includes that item. 7 | 8 | @example 9 | ``` 10 | import type {Includes} from 'type-fest'; 11 | 12 | type hasRed = Includes; 13 | ``` 14 | 15 | @category Array 16 | */ 17 | export type Includes = 18 | Value extends readonly [Value[0], ...infer rest] 19 | ? IsEqual extends true 20 | ? true 21 | : Includes 22 | : false; 23 | -------------------------------------------------------------------------------- /source/trim.d.ts: -------------------------------------------------------------------------------- 1 | import type {Whitespace} from './internal'; 2 | 3 | /** 4 | Remove spaces from the left side. 5 | */ 6 | type TrimLeft = V extends `${Whitespace}${infer R}` ? TrimLeft : V; 7 | 8 | /** 9 | Remove spaces from the right side. 10 | */ 11 | type TrimRight = V extends `${infer R}${Whitespace}` ? TrimRight : V; 12 | 13 | /** 14 | Remove leading and trailing spaces from a string. 15 | 16 | @example 17 | ``` 18 | import type {Trim} from 'type-fest'; 19 | 20 | Trim<' foo '> 21 | //=> 'foo' 22 | ``` 23 | 24 | @category String 25 | @category Template literal 26 | */ 27 | export type Trim = TrimLeft>; 28 | -------------------------------------------------------------------------------- /test-d/internal/is-union.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsUnion} from '../../source/internal'; 3 | 4 | expectType>(false); 5 | expectType>(false); 6 | expectType>(false); 7 | expectType>(false); 8 | expectType>(false); 9 | expectType>(false); 10 | expectType>(false); 11 | expectType>(false); 12 | expectType>(false); 13 | 14 | expectType>(true); 15 | expectType>(true); 16 | expectType>(true); 17 | expectType>(true); 18 | expectType>(true); 19 | -------------------------------------------------------------------------------- /test-d/is-never.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsNever} from '../index'; 3 | 4 | declare const _never: never; 5 | declare const something = 'something'; 6 | 7 | // `IsNever` should only be true for `any` 8 | expectType>(true); 9 | expectType>(true); 10 | expectType>(false); 11 | expectType>(false); 12 | expectType>(false); 13 | expectType>(false); 14 | expectType>(false); 15 | expectType>(false); 16 | expectType>(false); 17 | 18 | // Missing generic parameter 19 | // @ts-expect-error 20 | type A = IsNever; 21 | -------------------------------------------------------------------------------- /source/if-empty-object.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsEmptyObject} from './empty-object'; 2 | 3 | /** 4 | An if-else-like type that resolves depending on whether the given type is `{}`. 5 | 6 | @see {@link IsEmptyObject} 7 | 8 | @example 9 | ``` 10 | import type {IfEmptyObject} from 'type-fest'; 11 | 12 | type ShouldBeTrue = IfEmptyObject<{}>; 13 | //=> true 14 | 15 | type ShouldBeBar = IfEmptyObject<{key: any}, 'foo', 'bar'>; 16 | //=> 'bar' 17 | ``` 18 | 19 | @category Type Guard 20 | @category Utilities 21 | */ 22 | export type IfEmptyObject< 23 | T, 24 | TypeIfEmptyObject = true, 25 | TypeIfNotEmptyObject = false, 26 | > = IsEmptyObject extends true ? TypeIfEmptyObject : TypeIfNotEmptyObject; 27 | -------------------------------------------------------------------------------- /test-d/conditional-keys.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {ConditionalKeys} from '../index'; 3 | 4 | type Example = { 5 | a: string; 6 | b?: string | number; 7 | c?: string; 8 | d: Record; 9 | e: never; 10 | }; 11 | 12 | declare const exampleConditionalKeys: ConditionalKeys; 13 | expectType<'a'>(exampleConditionalKeys); 14 | 15 | declare const exampleConditionalKeysWithUndefined: ConditionalKeys; 16 | expectType<'a' | 'c'>(exampleConditionalKeysWithUndefined); 17 | 18 | declare const exampleConditionalKeysTargetingNever: ConditionalKeys; 19 | expectType<'e'>(exampleConditionalKeysTargetingNever); 20 | -------------------------------------------------------------------------------- /test-d/tagged-union.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable} from 'tsd'; 2 | import type {TaggedUnion} from '../index'; 3 | 4 | type Union = TaggedUnion<'tag', {str: {a: string} ; num: {b: number}}>; 5 | 6 | const first = { 7 | tag: 'str' as const, 8 | a: 'some-string', 9 | }; 10 | 11 | const second = { 12 | tag: 'num' as const, 13 | b: 1, 14 | }; 15 | 16 | expectAssignable(first); 17 | expectAssignable(second); 18 | 19 | const fails = { 20 | tag: 'num' as const, 21 | b: 'should not be string', 22 | }; 23 | 24 | const failsToo = { 25 | tag: 'str' as const, 26 | b: 2, 27 | }; 28 | 29 | expectNotAssignable(fails); 30 | expectNotAssignable(failsToo); 31 | -------------------------------------------------------------------------------- /test-d/is-unknown.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsUnknown} from '../index'; 3 | 4 | declare const _unknown: unknown; 5 | declare const something = 'something'; 6 | 7 | // `IsUnknown` should only be true for `any` 8 | expectType>(true); 9 | expectType>(true); 10 | expectType>(false); 11 | expectType>(false); 12 | expectType>(false); 13 | expectType>(false); 14 | expectType>(false); 15 | expectType>(false); 16 | expectType>(false); 17 | 18 | // Missing generic parameter 19 | // @ts-expect-error 20 | type A = IsUnknown; 21 | -------------------------------------------------------------------------------- /test-d/optional-keys-of.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {OptionalKeysOf} from '../index'; 3 | 4 | type TestType1 = { 5 | a: string; 6 | b?: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | a?: string; 11 | b?: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | a: string; 16 | b: boolean; 17 | }; 18 | 19 | type OptionalKeysOf1 = OptionalKeysOf; 20 | type OptionalKeysOf2 = OptionalKeysOf; 21 | type OptionalKeysOf3 = OptionalKeysOf; 22 | 23 | declare const test1: OptionalKeysOf1; 24 | declare const test2: OptionalKeysOf2; 25 | declare const test3: OptionalKeysOf3; 26 | 27 | expectType<'b'>(test1); 28 | expectType<'a' | 'b'>(test2); 29 | expectType(test3); 30 | -------------------------------------------------------------------------------- /test-d/required-keys-of.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {RequiredKeysOf} from '../index'; 3 | 4 | type TestType1 = { 5 | a: string; 6 | b?: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | a?: string; 11 | b?: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | a: string; 16 | b: boolean; 17 | }; 18 | 19 | type RequiredKeysOf1 = RequiredKeysOf; 20 | type RequiredKeysOf2 = RequiredKeysOf; 21 | type RequiredKeysOf3 = RequiredKeysOf; 22 | 23 | declare const test1: RequiredKeysOf1; 24 | declare const test2: RequiredKeysOf2; 25 | declare const test3: RequiredKeysOf3; 26 | 27 | expectType<'a'>(test1); 28 | expectType(test2); 29 | expectType<'a' | 'b'>(test3); 30 | -------------------------------------------------------------------------------- /test-d/has-optional-keys.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {HasOptionalKeys} from '../index'; 3 | 4 | type TestType1 = { 5 | a: string; 6 | b?: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | a?: string; 11 | b?: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | a: string; 16 | b: boolean; 17 | }; 18 | 19 | type HasOptionalKeys1 = HasOptionalKeys; 20 | type HasOptionalKeys2 = HasOptionalKeys; 21 | type HasOptionalKeys3 = HasOptionalKeys; 22 | 23 | declare const test1: HasOptionalKeys1; 24 | declare const test2: HasOptionalKeys2; 25 | declare const test3: HasOptionalKeys3; 26 | 27 | expectType(test1); 28 | expectType(test2); 29 | expectType(test3); 30 | -------------------------------------------------------------------------------- /test-d/has-required-keys.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {HasRequiredKeys} from '../index'; 3 | 4 | type TestType1 = { 5 | a: string; 6 | b?: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | a?: string; 11 | b?: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | a: string; 16 | b: boolean; 17 | }; 18 | 19 | type HasRequiredKeys1 = HasRequiredKeys; 20 | type HasRequiredKeys2 = HasRequiredKeys; 21 | type HasRequiredKeys3 = HasRequiredKeys; 22 | 23 | declare const test1: HasRequiredKeys1; 24 | declare const test2: HasRequiredKeys2; 25 | declare const test3: HasRequiredKeys3; 26 | 27 | expectType(test1); 28 | expectType(test2); 29 | expectType(test3); 30 | -------------------------------------------------------------------------------- /test-d/internal/has-multiple-call-signatures.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {HasMultipleCallSignatures} from '../../source/internal'; 3 | 4 | type Overloaded = { 5 | (foo: number): string; 6 | (foo: string, bar: number): number; 7 | }; 8 | 9 | type Overloaded2 = { 10 | (foo: number | undefined): string; 11 | // eslint-disable-next-line @typescript-eslint/unified-signatures 12 | (foo: number): string; 13 | }; 14 | 15 | type Namespace = { 16 | (foo: number): string; 17 | baz: boolean[]; 18 | }; 19 | 20 | expectType({} as HasMultipleCallSignatures); 21 | expectType({} as HasMultipleCallSignatures); 22 | expectType({} as HasMultipleCallSignatures); 23 | -------------------------------------------------------------------------------- /test-d/readonly-keys-of.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {ReadonlyKeysOf} from '../index'; 3 | 4 | type TestType1 = { 5 | a: string; 6 | readonly b: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | readonly a: string; 11 | readonly b: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | a: string; 16 | b: boolean; 17 | }; 18 | 19 | type ReadonlyKeysOf1 = ReadonlyKeysOf; 20 | type ReadonlyKeysOf2 = ReadonlyKeysOf; 21 | type ReadonlyKeysOf3 = ReadonlyKeysOf; 22 | 23 | declare const test1: ReadonlyKeysOf1; 24 | declare const test2: ReadonlyKeysOf2; 25 | declare const test3: ReadonlyKeysOf3; 26 | 27 | expectType<'b'>(test1); 28 | expectType<'a' | 'b'>(test2); 29 | expectType(test3); 30 | -------------------------------------------------------------------------------- /test-d/writable-keys-of.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {WritableKeysOf} from '../index'; 3 | 4 | type TestType1 = { 5 | readonly a: string; 6 | b: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | a: string; 11 | b: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | readonly a: string; 16 | readonly b: boolean; 17 | }; 18 | 19 | type WritableKeysOf1 = WritableKeysOf; 20 | type WritableKeysOf2 = WritableKeysOf; 21 | type WritableKeysOf3 = WritableKeysOf; 22 | 23 | declare const test1: WritableKeysOf1; 24 | declare const test2: WritableKeysOf2; 25 | declare const test3: WritableKeysOf3; 26 | 27 | expectType<'b'>(test1); 28 | expectType<'a' | 'b'>(test2); 29 | expectType(test3); 30 | -------------------------------------------------------------------------------- /test-d/snake-case.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {SnakeCase} from '../index'; 3 | 4 | const snakeFromCamel: SnakeCase<'fooBar'> = 'foo_bar'; 5 | expectType<'foo_bar'>(snakeFromCamel); 6 | 7 | const snakeFromPascal: SnakeCase<'FooBar'> = 'foo_bar'; 8 | expectType<'foo_bar'>(snakeFromPascal); 9 | 10 | const snakeFromKebab: SnakeCase<'foo-bar'> = 'foo_bar'; 11 | expectType<'foo_bar'>(snakeFromKebab); 12 | 13 | const snakeFromSpace: SnakeCase<'foo bar'> = 'foo_bar'; 14 | expectType<'foo_bar'>(snakeFromSpace); 15 | 16 | const snakeFromSnake: SnakeCase<'foo_bar'> = 'foo_bar'; 17 | expectType<'foo_bar'>(snakeFromSnake); 18 | 19 | const noSnakeFromMono: SnakeCase<'foobar'> = 'foobar'; 20 | expectType<'foobar'>(noSnakeFromMono); 21 | -------------------------------------------------------------------------------- /test-d/has-readonly-keys.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {HasReadonlyKeys} from '../index'; 3 | 4 | type TestType1 = { 5 | a: string; 6 | readonly b: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | readonly a: string; 11 | readonly b: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | a: string; 16 | b: boolean; 17 | }; 18 | 19 | type HasReadonlyKeys1 = HasReadonlyKeys; 20 | type HasReadonlyKeys2 = HasReadonlyKeys; 21 | type HasReadonlyKeys3 = HasReadonlyKeys; 22 | 23 | declare const test1: HasReadonlyKeys1; 24 | declare const test2: HasReadonlyKeys2; 25 | declare const test3: HasReadonlyKeys3; 26 | 27 | expectType(test1); 28 | expectType(test2); 29 | expectType(test3); 30 | -------------------------------------------------------------------------------- /test-d/has-writable-keys.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {HasWritableKeys} from '../index'; 3 | 4 | type TestType1 = { 5 | a: string; 6 | readonly b: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | readonly a: string; 11 | readonly b: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | a: string; 16 | b: boolean; 17 | }; 18 | 19 | type HasWritableKeys1 = HasWritableKeys; 20 | type HasWritableKeys2 = HasWritableKeys; 21 | type HasWritableKeys3 = HasWritableKeys; 22 | 23 | declare const test1: HasWritableKeys1; 24 | declare const test2: HasWritableKeys2; 25 | declare const test3: HasWritableKeys3; 26 | 27 | expectType(test1); 28 | expectType(test2); 29 | expectType(test3); 30 | -------------------------------------------------------------------------------- /test-d/non-empty-object.ts: -------------------------------------------------------------------------------- 1 | import {expectNever, expectType} from 'tsd'; 2 | import type {NonEmptyObject, RequireAtLeastOne} from '../index'; 3 | 4 | type TestType1 = { 5 | a: string; 6 | b: boolean; 7 | }; 8 | 9 | type TestType2 = { 10 | a?: string; 11 | b?: boolean; 12 | }; 13 | 14 | type TestType3 = { 15 | a: string; 16 | b?: boolean; 17 | }; 18 | 19 | type TestType4 = {}; 20 | 21 | declare const test1: NonEmptyObject; 22 | declare const test2: NonEmptyObject; 23 | declare const test3: NonEmptyObject; 24 | declare const test4: NonEmptyObject; 25 | 26 | expectType(test1); 27 | expectType>(test2); 28 | expectType(test3); 29 | expectNever(test4); 30 | -------------------------------------------------------------------------------- /test-d/pascal-cased-properties.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {PascalCasedProperties} from '../index'; 3 | 4 | declare const foo: PascalCasedProperties<{helloWorld: {fooBar: string}}>; 5 | expectType<{HelloWorld: {fooBar: string}}>(foo); 6 | 7 | declare const bar: PascalCasedProperties>; 8 | expectType>(bar); 9 | 10 | declare const fooBar: PascalCasedProperties<() => {a: string}>; 11 | expectType<() => {a: string}>(fooBar); 12 | 13 | // Verify example 14 | type User = { 15 | userId: number; 16 | userName: string; 17 | }; 18 | const result: PascalCasedProperties = { 19 | UserId: 1, 20 | UserName: 'Tom', 21 | }; 22 | expectType>(result); 23 | -------------------------------------------------------------------------------- /test-d/pick-index-signature.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {PickIndexSignature, Simplify} from '../index'; 3 | 4 | declare const symbolKey: unique symbol; 5 | 6 | type Foo = { 7 | [x: string]: unknown; 8 | [x: number]: unknown; 9 | [x: symbol]: unknown; 10 | [x: `head-${string}`]: string; 11 | [x: `${string}-tail`]: string; 12 | [x: `head-${string}-tail`]: string; 13 | [x: `${bigint}`]: string; 14 | [x: `embedded-${number}`]: string; 15 | }; 16 | 17 | type Bar = { 18 | ['snake-case-key']: string; 19 | [symbolKey]: string; 20 | foo: 'bar'; 21 | qux?: 'baz'; 22 | }; 23 | 24 | type FooBar = Simplify; 25 | 26 | declare const indexSignature: PickIndexSignature; 27 | 28 | expectType(indexSignature); 29 | -------------------------------------------------------------------------------- /source/array-values.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Provides all values for a constant array or tuple. 3 | 4 | Use-case: This type is useful when working with constant arrays or tuples and you want to enforce type-safety with their values. 5 | 6 | @example 7 | ``` 8 | import type {ArrayValues, ArrayIndices} from 'type-fest'; 9 | 10 | const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] as const; 11 | 12 | type WeekdayName = ArrayValues; 13 | type Weekday = ArrayIndices; 14 | 15 | const getWeekdayName = (day: Weekday): WeekdayName => weekdays[day]; 16 | ``` 17 | 18 | @see {@link ArrayIndices} 19 | 20 | @category Array 21 | */ 22 | export type ArrayValues = T[number]; 23 | -------------------------------------------------------------------------------- /test-d/int-closed-range.ts: -------------------------------------------------------------------------------- 1 | import {expectType, expectAssignable} from 'tsd'; 2 | import type {IntClosedRange} from '../source/int-closed-range'; 3 | 4 | declare const test: IntClosedRange<0, 5>; 5 | expectType<0 | 1 | 2 | 3 | 4 | 5>(test); 6 | 7 | declare const startTest: IntClosedRange<5, 10>; 8 | expectType<5 | 6 | 7 | 8 | 9 | 10>(startTest); 9 | 10 | declare const stepTest1: IntClosedRange<10, 20, 2>; 11 | expectType<10 | 12 | 14 | 16 | 18 | 20>(stepTest1); 12 | 13 | // Test for step > end - start 14 | declare const stepTest2: IntClosedRange<10, 20, 100>; 15 | expectType<10>(stepTest2); 16 | 17 | type Int0_998 = IntClosedRange<0, 998>; 18 | declare const maxNumberTest: Int0_998; 19 | expectAssignable(maxNumberTest); 20 | expectAssignable(998); 21 | -------------------------------------------------------------------------------- /test-d/union-to-intersection.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectType} from 'tsd'; 2 | import type {UnionToIntersection} from '../index'; 3 | 4 | declare const intersection1: UnionToIntersection<{a: string} | {b: number}>; 5 | expectAssignable<{a: string; b: number}>(intersection1); 6 | 7 | // Creates a union of matching properties. 8 | declare const intersection2: UnionToIntersection<{a: string} | {b: number} | {a: () => void}>; 9 | expectAssignable<{a: string | (() => void); b: number}>(intersection2); 10 | 11 | // It's possible to index by the resulting type. 12 | type ObjectsUnion = {a: string; z: string} | {b: string; z: string} | {c: string; z: string}; 13 | declare const value: ObjectsUnion[UnionToIntersection]; 14 | expectType(value); 15 | -------------------------------------------------------------------------------- /source/arrayable.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Create a type that represents either the value or an array of the value. 3 | 4 | @see Promisable 5 | 6 | @example 7 | ``` 8 | import type {Arrayable} from 'type-fest'; 9 | 10 | function bundle(input: string, output: Arrayable) { 11 | const outputList = Array.isArray(output) ? output : [output]; 12 | 13 | // … 14 | 15 | for (const output of outputList) { 16 | console.log(`write to: ${output}`); 17 | } 18 | } 19 | 20 | bundle('src/index.js', 'dist/index.js'); 21 | bundle('src/index.js', ['dist/index.cjs', 'dist/index.mjs']); 22 | ``` 23 | 24 | @category Array 25 | */ 26 | export type Arrayable = 27 | T 28 | // TODO: Use `readonly T[]` when this issue is resolved: https://github.com/microsoft/TypeScript/issues/17002 29 | | T[]; 30 | -------------------------------------------------------------------------------- /source/has-optional-keys.d.ts: -------------------------------------------------------------------------------- 1 | import type {OptionalKeysOf} from './optional-keys-of'; 2 | 3 | /** 4 | Creates a type that represents `true` or `false` depending on whether the given type has any optional fields. 5 | 6 | This is useful when you want to create an API whose behavior depends on the presence or absence of optional fields. 7 | 8 | @example 9 | ``` 10 | import type {HasOptionalKeys, OptionalKeysOf} from 'type-fest'; 11 | 12 | type UpdateService = { 13 | removeField: HasOptionalKeys extends true 14 | ? (field: OptionalKeysOf) => Promise 15 | : never 16 | } 17 | ``` 18 | 19 | @category Utilities 20 | */ 21 | export type HasOptionalKeys = OptionalKeysOf extends never ? false : true; 22 | -------------------------------------------------------------------------------- /source/has-readonly-keys.d.ts: -------------------------------------------------------------------------------- 1 | import type {ReadonlyKeysOf} from './readonly-keys-of'; 2 | 3 | /** 4 | Creates a type that represents `true` or `false` depending on whether the given type has any readonly fields. 5 | 6 | This is useful when you want to create an API whose behavior depends on the presence or absence of readonly fields. 7 | 8 | @example 9 | ``` 10 | import type {HasReadonlyKeys, ReadonlyKeysOf} from 'type-fest'; 11 | 12 | type UpdateService = { 13 | removeField: HasReadonlyKeys extends true 14 | ? (field: ReadonlyKeysOf) => Promise 15 | : never 16 | } 17 | ``` 18 | 19 | @category Utilities 20 | */ 21 | export type HasReadonlyKeys = ReadonlyKeysOf extends never ? false : true; 22 | -------------------------------------------------------------------------------- /source/has-writable-keys.d.ts: -------------------------------------------------------------------------------- 1 | import type {WritableKeysOf} from './writable-keys-of'; 2 | 3 | /** 4 | Creates a type that represents `true` or `false` depending on whether the given type has any writable fields. 5 | 6 | This is useful when you want to create an API whose behavior depends on the presence or absence of writable fields. 7 | 8 | @example 9 | ``` 10 | import type {HasWritableKeys, WritableKeysOf} from 'type-fest'; 11 | 12 | type UpdateService = { 13 | removeField: HasWritableKeys extends true 14 | ? (field: WritableKeysOf) => Promise 15 | : never 16 | } 17 | ``` 18 | 19 | @category Utilities 20 | */ 21 | export type HasWritableKeys = WritableKeysOf extends never ? false : true; 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1 new type.yml: -------------------------------------------------------------------------------- 1 | name: 💡 Suggest new type 2 | description: '​‌‍⁠ ' # Magic whitespace to hide this required field 3 | labels: 'type addition' 4 | 5 | body: 6 | - type: textarea 7 | id: description 8 | validations: 9 | required: true 10 | attributes: 11 | label: Type description + examples 12 | 13 | - type: textarea 14 | id: type 15 | attributes: 16 | label: Type source 17 | description: If you already have the type source, enter it here as a starting point for a the discussion 18 | 19 | - id: requirements 20 | type: checkboxes 21 | attributes: 22 | label: Search existing types and issues first 23 | options: 24 | - label: I tried my best to look for it 25 | required: true 26 | -------------------------------------------------------------------------------- /source/readonly-keys-of.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsEqual} from './is-equal'; 2 | 3 | /** 4 | Extract all readonly keys from the given type. 5 | 6 | This is useful when you want to create a new type that contains readonly keys only. 7 | 8 | @example 9 | ``` 10 | import type {ReadonlyKeysOf} from 'type-fest'; 11 | 12 | interface User { 13 | name: string; 14 | surname: string; 15 | readonly id: number; 16 | } 17 | 18 | type UpdateResponse = Pick>; 19 | 20 | const update1: UpdateResponse = { 21 | id: 123, 22 | }; 23 | ``` 24 | 25 | @category Utilities 26 | */ 27 | export type ReadonlyKeysOf = NonNullable<{ 28 | [P in keyof T]: IsEqual<{[Q in P]: T[P]}, {readonly [Q in P]: T[P]}> extends true ? P : never 29 | }[keyof T]>; 30 | -------------------------------------------------------------------------------- /source/unknown-record.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Represents an object with `unknown` value. You probably want this instead of `{}`. 3 | 4 | Use case: You have an object whose keys and values are unknown to you. 5 | 6 | @example 7 | ``` 8 | import type {UnknownRecord} from 'type-fest'; 9 | 10 | function toJson(object: UnknownRecord) { 11 | return JSON.stringify(object); 12 | } 13 | 14 | toJson({hello: 'world'}); 15 | //=> '{"hello":"world"}' 16 | 17 | function isObject(value: unknown): value is UnknownRecord { 18 | return typeof value === 'object' && value !== null; 19 | } 20 | 21 | isObject({hello: 'world'}); 22 | //=> true 23 | 24 | isObject('hello'); 25 | //=> false 26 | ``` 27 | 28 | @category Type 29 | @category Object 30 | */ 31 | export type UnknownRecord = Record; 32 | -------------------------------------------------------------------------------- /source/global-this.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Declare locally scoped properties on `globalThis`. 3 | 4 | When defining a global variable in a declaration file is inappropriate, it can be helpful to define a `type` or `interface` (say `ExtraGlobals`) with the global variable and then cast `globalThis` via code like `globalThis as unknown as ExtraGlobals`. 5 | 6 | Instead of casting through `unknown`, you can update your `type` or `interface` to extend `GlobalThis` and then directly cast `globalThis`. 7 | 8 | @example 9 | ``` 10 | import type {GlobalThis} from 'type-fest'; 11 | 12 | type ExtraGlobals = GlobalThis & { 13 | readonly GLOBAL_TOKEN: string; 14 | }; 15 | 16 | (globalThis as ExtraGlobals).GLOBAL_TOKEN; 17 | ``` 18 | 19 | @category Type 20 | */ 21 | export type GlobalThis = typeof globalThis; 22 | -------------------------------------------------------------------------------- /.github/workflows/ts-canary.yml: -------------------------------------------------------------------------------- 1 | name: TypeScript Canary 2 | on: 3 | schedule: 4 | # Every Thursday at 21.15 5 | - cron: '15 21 * * 4' 6 | workflow_dispatch: 7 | jobs: 8 | types: 9 | name: TypeScript ${{ matrix.typescript-version }} 10 | runs-on: ubuntu-latest 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | typescript-version: 15 | - next 16 | - latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: actions/setup-node@v4 20 | with: 21 | node-version: lts/* 22 | - run: npm install 23 | - run: npm install typescript@${{ matrix.typescript-version }} 24 | - name: show installed typescript version 25 | run: npm list typescript --depth=0 26 | - run: npx tsc 27 | -------------------------------------------------------------------------------- /source/snake-cased-properties.d.ts: -------------------------------------------------------------------------------- 1 | import type {DelimiterCasedProperties} from './delimiter-cased-properties'; 2 | 3 | /** 4 | Convert object properties to snake case but not recursively. 5 | 6 | This can be useful when, for example, converting some API types from a different style. 7 | 8 | @see SnakeCase 9 | @see SnakeCasedPropertiesDeep 10 | 11 | @example 12 | ``` 13 | import type {SnakeCasedProperties} from 'type-fest'; 14 | 15 | interface User { 16 | userId: number; 17 | userName: string; 18 | } 19 | 20 | const result: SnakeCasedProperties = { 21 | user_id: 1, 22 | user_name: 'Tom', 23 | }; 24 | ``` 25 | 26 | @category Change case 27 | @category Template literal 28 | @category Object 29 | */ 30 | export type SnakeCasedProperties = DelimiterCasedProperties; 31 | -------------------------------------------------------------------------------- /source/kebab-cased-properties.d.ts: -------------------------------------------------------------------------------- 1 | import type {DelimiterCasedProperties} from './delimiter-cased-properties'; 2 | 3 | /** 4 | Convert object properties to kebab case but not recursively. 5 | 6 | This can be useful when, for example, converting some API types from a different style. 7 | 8 | @see KebabCase 9 | @see KebabCasedPropertiesDeep 10 | 11 | @example 12 | ``` 13 | import type {KebabCasedProperties} from 'type-fest'; 14 | 15 | interface User { 16 | userId: number; 17 | userName: string; 18 | } 19 | 20 | const result: KebabCasedProperties = { 21 | 'user-id': 1, 22 | 'user-name': 'Tom', 23 | }; 24 | ``` 25 | 26 | @category Change case 27 | @category Template literal 28 | @category Object 29 | */ 30 | export type KebabCasedProperties = DelimiterCasedProperties; 31 | -------------------------------------------------------------------------------- /source/single-key-object.d.ts: -------------------------------------------------------------------------------- 1 | import type {IfEmptyObject} from './if-empty-object'; 2 | import type {IsUnion} from './internal'; 3 | 4 | /** 5 | Create a type that only accepts an object with a single key. 6 | 7 | @example 8 | ``` 9 | import type {SingleKeyObject} from 'type-fest'; 10 | 11 | const someFunction = (parameter: SingleKeyObject) => {}; 12 | 13 | someFunction({ 14 | value: true 15 | }); 16 | 17 | someFunction({ 18 | value: true, 19 | otherKey: true 20 | }); 21 | // Error: Argument of type '{value: boolean; otherKey: boolean}' is not assignable to parameter of type 'never'.ts(2345) 22 | ``` 23 | 24 | @category Object 25 | */ 26 | export type SingleKeyObject = 27 | IsUnion extends true 28 | ? never 29 | : IfEmptyObject; 30 | -------------------------------------------------------------------------------- /test-d/array-indices.ts: -------------------------------------------------------------------------------- 1 | import {expectNotAssignable, expectType, expectAssignable} from 'tsd'; 2 | import type {ArrayIndices} from '../index'; 3 | 4 | const values = ['a', 'b', 'c'] as const; 5 | type ValueKeys = ArrayIndices; 6 | 7 | declare const test: 0 | 1 | 2; 8 | expectType(test); 9 | 10 | expectAssignable(0); 11 | expectAssignable(1); 12 | expectAssignable(2); 13 | 14 | expectNotAssignable(-1); 15 | expectNotAssignable(3); 16 | 17 | type TupleKeys = ArrayIndices<['a', 2]>; 18 | 19 | declare const testTuple: 0 | 1; 20 | expectType(testTuple); 21 | 22 | expectAssignable(0); 23 | expectAssignable(1); 24 | 25 | expectNotAssignable(-1); 26 | expectNotAssignable(2); 27 | -------------------------------------------------------------------------------- /test-d/delimiter-cased-properties.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {DelimiterCasedProperties} from '../index'; 3 | 4 | declare const foo: DelimiterCasedProperties<{helloWorld: {fooBar: string}}, '/'>; 5 | expectType<{'hello/world': {fooBar: string}}>(foo); 6 | 7 | declare const bar: DelimiterCasedProperties, '-'>; 8 | expectType>(bar); 9 | 10 | declare const fooBar: DelimiterCasedProperties<() => {a: string}, '-'>; 11 | expectType<() => {a: string}>(fooBar); 12 | 13 | // Verify example 14 | type User = { 15 | userId: number; 16 | userName: string; 17 | }; 18 | const result: DelimiterCasedProperties = { 19 | 'user-id': 1, 20 | 'user-name': 'Tom', 21 | }; 22 | expectType>(result); 23 | -------------------------------------------------------------------------------- /test-d/is-float.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsFloat, PositiveInfinity} from '../index'; 3 | 4 | expectType({} as IsFloat<0>); 5 | expectType({} as IsFloat<1>); 6 | expectType({} as IsFloat<1.0>); // eslint-disable-line unicorn/no-zero-fractions 7 | expectType({} as IsFloat<1.5>); 8 | expectType({} as IsFloat<-1>); 9 | expectType({} as IsFloat); 10 | expectType({} as IsFloat<0o10>); 11 | expectType({} as IsFloat<1n>); 12 | expectType({} as IsFloat<0n>); 13 | expectType({} as IsFloat<0b10>); 14 | expectType({} as IsFloat<0x10>); 15 | expectType({} as IsFloat<1e+100>); 16 | expectType({} as IsFloat); 17 | expectType({} as IsFloat); 18 | -------------------------------------------------------------------------------- /source/async-return-type.d.ts: -------------------------------------------------------------------------------- 1 | type AsyncFunction = (...arguments_: any[]) => Promise; 2 | 3 | /** 4 | Unwrap the return type of a function that returns a `Promise`. 5 | 6 | There has been [discussion](https://github.com/microsoft/TypeScript/pull/35998) about implementing this type in TypeScript. 7 | 8 | @example 9 | ```ts 10 | import type {AsyncReturnType} from 'type-fest'; 11 | import {asyncFunction} from 'api'; 12 | 13 | // This type resolves to the unwrapped return type of `asyncFunction`. 14 | type Value = AsyncReturnType; 15 | 16 | async function doSomething(value: Value) {} 17 | 18 | asyncFunction().then(value => doSomething(value)); 19 | ``` 20 | 21 | @category Async 22 | */ 23 | export type AsyncReturnType = Awaited>; 24 | -------------------------------------------------------------------------------- /source/writable-keys-of.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsEqual} from './is-equal'; 2 | 3 | /** 4 | Extract all writable keys from the given type. 5 | 6 | This is useful when you want to create a new type that contains writable keys only. 7 | 8 | @example 9 | ``` 10 | import type {WritableKeysOf} from 'type-fest'; 11 | 12 | interface User { 13 | name: string; 14 | surname: string; 15 | readonly id: number; 16 | } 17 | 18 | type UpdateRequest = Pick>; 19 | 20 | const update1: UpdateRequest = { 21 | name: 'Alice', 22 | surname: 'Acme', 23 | }; 24 | ``` 25 | 26 | @category Utilities 27 | */ 28 | export type WritableKeysOf = NonNullable<{ 29 | [P in keyof T]: IsEqual<{[Q in P]: T[P]}, {readonly [Q in P]: T[P]}> extends false ? P : never 30 | }[keyof T]>; 31 | -------------------------------------------------------------------------------- /source/array-tail.d.ts: -------------------------------------------------------------------------------- 1 | import type {UnknownArrayOrTuple} from './internal'; 2 | 3 | /** 4 | Extracts the type of an array or tuple minus the first element. 5 | 6 | @example 7 | ``` 8 | import type {ArrayTail} from 'type-fest'; 9 | 10 | declare const curry: ( 11 | function_: (...arguments_: Arguments) => Return, 12 | ...arguments_: ArrayTail 13 | ) => (...arguments_: ArrayTail) => Return; 14 | 15 | const add = (a: number, b: number) => a + b; 16 | 17 | const add3 = curry(add, 3); 18 | 19 | add3(4); 20 | //=> 7 21 | ``` 22 | 23 | @category Array 24 | */ 25 | export type ArrayTail = TArray extends readonly [unknown?, ...infer Tail] 26 | ? keyof TArray & `${number}` extends never 27 | ? [] 28 | : Tail 29 | : []; 30 | -------------------------------------------------------------------------------- /test-d/internal/is-numeric.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsNumeric} from '../../source/internal'; 3 | 4 | expectType>(false); 5 | expectType>(true); 6 | expectType>(true); 7 | expectType>(true); 8 | expectType>(true); 9 | expectType>(true); 10 | expectType>(true); 11 | expectType>(true); 12 | expectType>(true); 13 | expectType>(true); 14 | expectType>(false); 15 | expectType>(false); 16 | expectType>(false); 17 | expectType>(false); 18 | expectType>(false); 19 | expectType>(false); 20 | expectType>(false); 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2 bug report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Report bug 2 | description: '​‌‍⁠ ' # Magic whitespace to hide this required field 3 | labels: bug 4 | 5 | body: 6 | - type: textarea 7 | id: description 8 | validations: 9 | required: true 10 | attributes: 11 | label: Bug description 12 | 13 | - type: input 14 | id: repro 15 | validations: 16 | required: true 17 | attributes: 18 | label: Repro 19 | description: | 20 | Open [this playground](https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBDAnmApnA3gUQB4GMVgwC+cAZlBCHAORKoC0pKAzjNQNwCwAUD3WgDEIEOAF4MPAJABXAHbBc0WQC44rKMFkBzLt0lQAhpoBGEAO6rTEADYoDs3UV19kaAHIQASkdmmzYuBx8QgAeIQgAGhpDE3NqAD5dOGS4AHpUuAA9AH4eIA), write a piece of code that fails your expectations, click "Share", and paste the URL here 21 | -------------------------------------------------------------------------------- /source/split.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Represents an array of strings split using a given character or character set. 3 | 4 | Use-case: Defining the return type of a method like `String.prototype.split`. 5 | 6 | @example 7 | ``` 8 | import type {Split} from 'type-fest'; 9 | 10 | declare function split(string: S, separator: D): Split; 11 | 12 | type Item = 'foo' | 'bar' | 'baz' | 'waldo'; 13 | const items = 'foo,bar,baz,waldo'; 14 | let array: Item[]; 15 | 16 | array = split(items, ','); 17 | ``` 18 | 19 | @category String 20 | @category Template literal 21 | */ 22 | export type Split< 23 | S extends string, 24 | Delimiter extends string, 25 | > = S extends `${infer Head}${Delimiter}${infer Tail}` 26 | ? [Head, ...Split] 27 | : S extends Delimiter 28 | ? [] 29 | : [S]; 30 | -------------------------------------------------------------------------------- /test-d/is-integer.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsInteger, PositiveInfinity} from '../index'; 3 | 4 | expectType({} as IsInteger<0>); 5 | expectType({} as IsInteger<1>); 6 | expectType({} as IsInteger<1.0>); // eslint-disable-line unicorn/no-zero-fractions 7 | expectType({} as IsInteger<1.5>); 8 | expectType({} as IsInteger<-1>); 9 | expectType({} as IsInteger); 10 | expectType({} as IsInteger<0o10>); 11 | expectType({} as IsInteger<1n>); 12 | expectType({} as IsInteger<0n>); 13 | expectType({} as IsInteger<0b10>); 14 | expectType({} as IsInteger<0x10>); 15 | expectType({} as IsInteger<1e+100>); 16 | expectType({} as IsInteger); 17 | expectType({} as IsInteger); 18 | -------------------------------------------------------------------------------- /test-d/tsconfig-json.ts: -------------------------------------------------------------------------------- 1 | import {expectType, expectAssignable} from 'tsd'; 2 | import type {Jsonifiable, TsConfigJson} from '../index'; 3 | 4 | const tsConfig: TsConfigJson = {}; 5 | 6 | expectType(tsConfig.compileOnSave); 7 | expectType(tsConfig.compilerOptions); 8 | expectType(tsConfig.exclude); 9 | expectType(tsConfig.extends); 10 | expectType(tsConfig.files); 11 | expectType(tsConfig.include); 12 | expectType(tsConfig.references); 13 | expectType(tsConfig.typeAcquisition); 14 | expectAssignable(tsConfig); 15 | 16 | expectType(tsConfig.compilerOptions?.noCheck); 17 | -------------------------------------------------------------------------------- /source/array-indices.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Provides valid indices for a constant array or tuple. 3 | 4 | Use-case: This type is useful when working with constant arrays or tuples and you want to enforce type-safety for accessing elements by their indices. 5 | 6 | @example 7 | ``` 8 | import type {ArrayIndices, ArrayValues} from 'type-fest'; 9 | 10 | const weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] as const; 11 | 12 | type Weekday = ArrayIndices; 13 | type WeekdayName = ArrayValues; 14 | 15 | const getWeekdayName = (day: Weekday): WeekdayName => weekdays[day]; 16 | ``` 17 | 18 | @see {@link ArrayValues} 19 | 20 | @category Array 21 | */ 22 | export type ArrayIndices = 23 | Exclude['length'], Element['length']>; 24 | -------------------------------------------------------------------------------- /source/is-float.d.ts: -------------------------------------------------------------------------------- 1 | import type {Zero} from './numeric'; 2 | 3 | /** 4 | Returns a boolean for whether the given number is a float, like `1.5` or `-1.5`. 5 | 6 | It returns `false` for `Infinity`. 7 | 8 | Use-case: 9 | - If you want to make a conditional branch based on the result of whether a number is a float or not. 10 | 11 | @example 12 | ``` 13 | type Float = IsFloat<1.5>; 14 | //=> true 15 | 16 | type IntegerWithDecimal = IsInteger<1.0>; 17 | //=> false 18 | 19 | type NegativeFloat = IsInteger<-1.5>; 20 | //=> true 21 | 22 | type Infinity_ = IsInteger; 23 | //=> false 24 | ``` 25 | */ 26 | export type IsFloat = 27 | T extends number 28 | ? `${T}` extends `${infer _Sign extends '' | '-'}${number}.${infer Decimal extends number}` 29 | ? Decimal extends Zero 30 | ? false 31 | : true 32 | : false 33 | : false; 34 | -------------------------------------------------------------------------------- /test-d/int-range.ts: -------------------------------------------------------------------------------- 1 | import {expectType, expectAssignable} from 'tsd'; 2 | import type {IntRange} from '../source/int-range'; 3 | 4 | declare const test: IntRange<0, 5>; 5 | expectType<0 | 1 | 2 | 3 | 4>(test); 6 | 7 | declare const startTest: IntRange<5, 10>; 8 | expectType<5 | 6 | 7 | 8 | 9>(startTest); 9 | 10 | declare const stepTest1: IntRange<10, 20, 2>; 11 | expectType<10 | 12 | 14 | 16 | 18>(stepTest1); 12 | 13 | // Test for step > end - start 14 | declare const stepTest2: IntRange<10, 20, 100>; 15 | expectType<10>(stepTest2); 16 | 17 | declare const maxNumberTest: IntRange<0, 999>; 18 | expectAssignable(maxNumberTest); 19 | 20 | // Not yet supported. 21 | // declare const negative: IntRange<-1, 1>; 22 | // expectType<-1 | 0 | 1>(negative); 23 | 24 | // declare const negative2: IntRange<1, -1>; 25 | // expectType<-1 | 0 | 1>(negative2); 26 | -------------------------------------------------------------------------------- /test-d/require-exactly-one.ts: -------------------------------------------------------------------------------- 1 | import type {RequireExactlyOne} from '../index'; 2 | 3 | type SystemMessages = { 4 | default: string; 5 | 6 | macos: string; 7 | linux: string; 8 | 9 | optional?: string; 10 | }; 11 | 12 | type ValidMessages = RequireExactlyOne; 13 | declare const test: (_: ValidMessages) => void; 14 | 15 | test({macos: 'hey', default: 'hello'}); 16 | test({linux: 'sup', optional: 'howdy', default: 'hello'}); 17 | 18 | // @ts-expect-error 19 | test({}); 20 | // @ts-expect-error 21 | test({macos: 'hey', linux: 'sup', default: 'hello'}); 22 | 23 | declare const testWithoutKeys: (_: RequireExactlyOne<{a: number; b: number}>) => void; 24 | 25 | testWithoutKeys({a: 1}); 26 | testWithoutKeys({b: 2}); 27 | 28 | // @ts-expect-error 29 | testWithoutKeys({}); 30 | // @ts-expect-error 31 | testWithoutKeys({a: 1, b: 2}); 32 | -------------------------------------------------------------------------------- /test-d/except.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Except} from '../index'; 3 | 4 | declare const except: Except<{a: number; b: string}, 'b'>; 5 | expectType<{a: number}>(except); 6 | // @ts-expect-error 7 | const _a: unknown = except.b; 8 | 9 | const nonStrict = { 10 | a: 1, 11 | b: '2', 12 | }; 13 | 14 | const nonStrictAssignment: typeof except = nonStrict; // No error 15 | 16 | declare const strictExcept: Except<{a: number; b: string}, 'b', {requireExactProps: true}>; 17 | 18 | // @ts-expect-error 19 | const strictAssignment: typeof strictExcept = nonStrict; 20 | 21 | // Generic properties 22 | type Example = { 23 | [key: string]: unknown; 24 | foo: number; 25 | bar: string; 26 | }; 27 | 28 | const test: Except = {foo: 123, bar: 'asdf'}; 29 | expectType(test.foo); 30 | expectType(test['bar']); 31 | -------------------------------------------------------------------------------- /test-d/merge-exclusive.ts: -------------------------------------------------------------------------------- 1 | import {expectNotAssignable, expectAssignable} from 'tsd'; 2 | import type {MergeExclusive} from '../index'; 3 | 4 | type BaseOptions = { 5 | option?: string; 6 | }; 7 | 8 | type ExclusiveVariation1 = { 9 | exclusive1: boolean; 10 | } & BaseOptions; 11 | 12 | type ExclusiveVariation2 = { 13 | exclusive2: number; 14 | } & BaseOptions; 15 | 16 | type Options = MergeExclusive; 17 | 18 | const exclusiveVariation1: Options = {exclusive1: true}; 19 | const exclusiveVariation2: Options = {exclusive2: 1}; 20 | 21 | expectAssignable<{option?: string; exclusive1: boolean; exclusive2?: string}>( 22 | exclusiveVariation1, 23 | ); 24 | expectAssignable<{option?: string; exclusive1?: string; exclusive2: number}>( 25 | exclusiveVariation2, 26 | ); 27 | 28 | expectNotAssignable({exclusive1: true, exclusive2: 1}); 29 | -------------------------------------------------------------------------------- /test-d/conditional-pick.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {ConditionalPick, Primitive} from '../index'; 3 | 4 | class Awesome { 5 | name!: string; 6 | successes!: number; 7 | failures!: bigint; 8 | 9 | run(): void { 10 | // Empty 11 | } 12 | } 13 | 14 | type Example = { 15 | a: string; 16 | b?: string | number; 17 | c?: string; 18 | d: Record; 19 | }; 20 | 21 | declare const exampleConditionalPick: ConditionalPick; 22 | expectType< {a: string}>(exampleConditionalPick); 23 | 24 | declare const awesomeConditionalPick: ConditionalPick; 25 | expectType<{name: string; successes: number; failures: bigint}>(awesomeConditionalPick); 26 | 27 | declare const exampleConditionalPickWithUndefined: ConditionalPick; 28 | expectType<{a: string; c?: string}>(exampleConditionalPickWithUndefined); 29 | -------------------------------------------------------------------------------- /test-d/observable-like.ts: -------------------------------------------------------------------------------- 1 | import {expectType, expectAssignable} from 'tsd'; 2 | import type {ObservableLike} from '../index'; 3 | 4 | // eslint-disable-next-line no-use-extend-native/no-use-extend-native 5 | expectAssignable(Symbol.observable); 6 | 7 | const observable = (null as any) as ObservableLike; 8 | 9 | const subscription = observable.subscribe({ 10 | next() {}, // eslint-disable-line @typescript-eslint/no-empty-function 11 | }); 12 | expectType<{unsubscribe(): void}>(subscription); 13 | 14 | observable.subscribe({ 15 | next(value) { 16 | expectType(value); 17 | }, 18 | }); 19 | 20 | const observable2 = (null as any) as ObservableLike; 21 | 22 | observable2.subscribe({ 23 | next() {}, // eslint-disable-line @typescript-eslint/no-empty-function 24 | }); 25 | observable2.subscribe({ 26 | next(value) { 27 | expectType(value); 28 | }, 29 | }); 30 | -------------------------------------------------------------------------------- /test-d/string-repeat.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {StringRepeat} from '../index'; 3 | 4 | declare const unknown: unknown; 5 | 6 | expectType>(''); 7 | expectType>(unknown as never); 8 | expectType>(''); 9 | expectType>(unknown as never); 10 | expectType>(''); 11 | expectType>(unknown as string); 12 | expectType>(unknown as string); 13 | expectType>(unknown as never); 14 | expectType>(''); 15 | expectType>('0'); 16 | expectType>('00000'); 17 | expectType>(''); 18 | expectType>('012345-'); 19 | expectType>('012345-012345-012345-012345-012345-'); 20 | -------------------------------------------------------------------------------- /test-d/multidimensional-array.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {MultidimensionalArray} from '../index'; 3 | 4 | function createArray(dimensions: T): MultidimensionalArray { 5 | const root: unknown[] = []; 6 | 7 | let array = root; 8 | for (let dimension = 1; dimension < dimensions; ++dimension) { 9 | array[0] = []; 10 | array = array[0] as unknown[]; 11 | } 12 | 13 | return root as MultidimensionalArray; 14 | } 15 | 16 | const a: MultidimensionalArray = []; 17 | const b: MultidimensionalArray = []; 18 | const c = createArray(2); 19 | const d = createArray(7); 20 | 21 | a[0][0][0] = 42; 22 | 23 | type RecursiveArray = Array>; 24 | 25 | expectType(a); 26 | expectType>(b); 27 | expectType(c); 28 | expectType(d); 29 | -------------------------------------------------------------------------------- /script/test/source-files-extension.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable unicorn/prefer-module */ 2 | const fs = require('node:fs'); 3 | const process = require('node:process'); 4 | 5 | const checkSourceFilesExtension = async () => { 6 | try { 7 | const files = await fs.promises.readdir('source', {recursive: true}); 8 | 9 | let hasIncorrectFileExtension = false; 10 | for (const file of files) { 11 | if (!file.includes('.')) { 12 | continue; 13 | } 14 | 15 | if (!file.endsWith('.d.ts')) { 16 | hasIncorrectFileExtension = true; 17 | console.error(`source/${file} extension should be \`.d.ts\`.`); 18 | } 19 | } 20 | 21 | if (hasIncorrectFileExtension) { 22 | process.exitCode = 1; 23 | } 24 | } catch (error) { 25 | console.error(error); 26 | process.exitCode = 1; 27 | } 28 | }; 29 | 30 | // eslint-disable-next-line unicorn/prefer-top-level-await 31 | checkSourceFilesExtension(); 32 | -------------------------------------------------------------------------------- /test-d/keys-of-union.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {KeysOfUnion} from '../index'; 3 | 4 | // When passing types that are not unions, it behaves exactly as the `keyof` operator. 5 | 6 | type Example1 = { 7 | string: string; 8 | number: number; 9 | boolean: boolean; 10 | null: null; 11 | array: number[]; 12 | }; 13 | 14 | type Expected1 = keyof Example1; 15 | 16 | declare const actual1: KeysOfUnion; 17 | 18 | expectType(actual1); 19 | 20 | // When passing a type that is a union, it returns a union of all keys of all union members. 21 | 22 | type Example2 = { 23 | common: string; 24 | a: number; 25 | } | { 26 | common: string; 27 | b: string; 28 | } | { 29 | common: string; 30 | c: boolean; 31 | }; 32 | 33 | type Expected2 = 'common' | 'a' | 'b' | 'c'; 34 | 35 | declare const actual2: KeysOfUnion; 36 | 37 | expectType(actual2); 38 | -------------------------------------------------------------------------------- /source/internal/characters.d.ts: -------------------------------------------------------------------------------- 1 | export type UpperCaseCharacters = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'; 2 | 3 | export type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'; 4 | 5 | export type Whitespace = 6 | | '\u{9}' // '\t' 7 | | '\u{A}' // '\n' 8 | | '\u{B}' // '\v' 9 | | '\u{C}' // '\f' 10 | | '\u{D}' // '\r' 11 | | '\u{20}' // ' ' 12 | | '\u{85}' 13 | | '\u{A0}' 14 | | '\u{1680}' 15 | | '\u{2000}' 16 | | '\u{2001}' 17 | | '\u{2002}' 18 | | '\u{2003}' 19 | | '\u{2004}' 20 | | '\u{2005}' 21 | | '\u{2006}' 22 | | '\u{2007}' 23 | | '\u{2008}' 24 | | '\u{2009}' 25 | | '\u{200A}' 26 | | '\u{2028}' 27 | | '\u{2029}' 28 | | '\u{202F}' 29 | | '\u{205F}' 30 | | '\u{3000}' 31 | | '\u{FEFF}'; 32 | 33 | export type WordSeparators = '-' | '_' | Whitespace; 34 | -------------------------------------------------------------------------------- /source/promisable.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Create a type that represents either the value or the value wrapped in `PromiseLike`. 3 | 4 | Use-cases: 5 | - A function accepts a callback that may either return a value synchronously or may return a promised value. 6 | - This type could be the return type of `Promise#then()`, `Promise#catch()`, and `Promise#finally()` callbacks. 7 | 8 | Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/31394) if you want to have this type as a built-in in TypeScript. 9 | 10 | @example 11 | ``` 12 | import type {Promisable} from 'type-fest'; 13 | 14 | async function logger(getLogEntry: () => Promisable): Promise { 15 | const entry = await getLogEntry(); 16 | console.log(entry); 17 | } 18 | 19 | logger(() => 'foo'); 20 | logger(() => Promise.resolve('bar')); 21 | ``` 22 | 23 | @category Async 24 | */ 25 | export type Promisable = T | PromiseLike; 26 | -------------------------------------------------------------------------------- /source/string-slice.d.ts: -------------------------------------------------------------------------------- 1 | import type {Join} from './join'; 2 | import type {ArraySlice} from './array-slice'; 3 | import type {StringToArray} from './internal'; 4 | 5 | /** 6 | Returns a string slice of a given range, just like `String#slice()`. 7 | 8 | @see {ArraySlice} 9 | 10 | @example 11 | ``` 12 | import type {StringSlice} from 'type-fest'; 13 | 14 | StringSlice<'abcde', 0, 2>; 15 | //=> 'ab' 16 | 17 | StringSlice<'abcde', 1>; 18 | //=> 'bcde' 19 | 20 | StringSlice<'abcde', 0, -1>; 21 | //=> 'abcd' 22 | 23 | StringSlice<'abcde', -2, -1>; 24 | //=> 'd' 25 | ``` 26 | 27 | @category String 28 | */ 29 | export type StringSlice< 30 | S extends string, 31 | Start extends number = 0, 32 | End extends number = StringToArray['length'], 33 | > = string extends S 34 | ? string[] 35 | : ArraySlice, Start, End> extends infer R extends readonly string[] 36 | ? Join 37 | : never; 38 | -------------------------------------------------------------------------------- /test-d/require-all-or-none.ts: -------------------------------------------------------------------------------- 1 | import type {RequireAllOrNone} from '../index'; 2 | 3 | type SystemMessages = { 4 | default: string; 5 | 6 | macos: string; 7 | linux: string; 8 | 9 | optional?: string; 10 | }; 11 | 12 | type ValidMessages = RequireAllOrNone; 13 | declare const test: (_: ValidMessages) => void; 14 | 15 | test({default: 'hello'}); 16 | test({macos: 'yo', linux: 'sup', optional: 'howdy', default: 'hello'}); 17 | 18 | // @ts-expect-error 19 | test({}); 20 | // @ts-expect-error 21 | test({macos: 'hey', default: 'hello'}); 22 | // @ts-expect-error 23 | test({linux: 'hey', default: 'hello'}); 24 | 25 | declare const testWithoutKeys: (_: RequireAllOrNone<{a: number; b: number}>) => void; 26 | 27 | testWithoutKeys({}); 28 | testWithoutKeys({a: 1, b: 2}); 29 | 30 | // @ts-expect-error 31 | testWithoutKeys({a: 1}); 32 | // @ts-expect-error 33 | testWithoutKeys({b: 2}); 34 | -------------------------------------------------------------------------------- /source/keys-of-union.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Create a union of all keys from a given type, even those exclusive to specific union members. 3 | 4 | Unlike the native `keyof` keyword, which returns keys present in **all** union members, this type returns keys from **any** member. 5 | 6 | @link https://stackoverflow.com/a/49402091 7 | 8 | @example 9 | ``` 10 | import type {KeysOfUnion} from 'type-fest'; 11 | 12 | type A = { 13 | common: string; 14 | a: number; 15 | }; 16 | 17 | type B = { 18 | common: string; 19 | b: string; 20 | }; 21 | 22 | type C = { 23 | common: string; 24 | c: boolean; 25 | }; 26 | 27 | type Union = A | B | C; 28 | 29 | type CommonKeys = keyof Union; 30 | //=> 'common' 31 | 32 | type AllKeys = KeysOfUnion; 33 | //=> 'common' | 'a' | 'b' | 'c' 34 | ``` 35 | 36 | @category Object 37 | */ 38 | export type KeysOfUnion = ObjectType extends unknown 39 | ? keyof ObjectType 40 | : never; 41 | -------------------------------------------------------------------------------- /source/snake-case.d.ts: -------------------------------------------------------------------------------- 1 | import type {DelimiterCase} from './delimiter-case'; 2 | 3 | /** 4 | Convert a string literal to snake-case. 5 | 6 | This can be useful when, for example, converting a camel-cased object property to a snake-cased SQL column name. 7 | 8 | @example 9 | ``` 10 | import type {SnakeCase} from 'type-fest'; 11 | 12 | // Simple 13 | 14 | const someVariable: SnakeCase<'fooBar'> = 'foo_bar'; 15 | 16 | // Advanced 17 | 18 | type SnakeCasedProperties = { 19 | [K in keyof T as SnakeCase]: T[K] 20 | }; 21 | 22 | interface ModelProps { 23 | isHappy: boolean; 24 | fullFamilyName: string; 25 | foo: number; 26 | } 27 | 28 | const dbResult: SnakeCasedProperties = { 29 | 'is_happy': true, 30 | 'full_family_name': 'Carla Smith', 31 | foo: 123 32 | }; 33 | ``` 34 | 35 | @category Change case 36 | @category Template literal 37 | */ 38 | export type SnakeCase = DelimiterCase; 39 | -------------------------------------------------------------------------------- /test-d/is-any.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsAny} from '../index'; 3 | 4 | declare const anything: any; 5 | declare const something = 'something'; 6 | 7 | // `IsAny` should only be true for `any` 8 | expectType>(true); 9 | expectType>(true); 10 | expectType>(false); 11 | expectType>(false); 12 | expectType>(false); 13 | expectType>(false); 14 | expectType>(false); 15 | expectType>(false); 16 | expectType>(false); 17 | 18 | // Missing generic parameter 19 | // @ts-expect-error 20 | type A = IsAny; 21 | 22 | // Verify that are no circular reference issues 23 | // https://github.com/sindresorhus/type-fest/issues/846 24 | type OnlyAny extends true ? any : never> = T; 25 | type B = OnlyAny; 26 | // @ts-expect-error 27 | type C = OnlyAny; 28 | -------------------------------------------------------------------------------- /source/kebab-case.d.ts: -------------------------------------------------------------------------------- 1 | import type {DelimiterCase} from './delimiter-case'; 2 | 3 | /** 4 | Convert a string literal to kebab-case. 5 | 6 | This can be useful when, for example, converting a camel-cased object property to a kebab-cased CSS class name or a command-line flag. 7 | 8 | @example 9 | ``` 10 | import type {KebabCase} from 'type-fest'; 11 | 12 | // Simple 13 | 14 | const someVariable: KebabCase<'fooBar'> = 'foo-bar'; 15 | 16 | // Advanced 17 | 18 | type KebabCasedProperties = { 19 | [K in keyof T as KebabCase]: T[K] 20 | }; 21 | 22 | interface CliOptions { 23 | dryRun: boolean; 24 | includeFile: string; 25 | foo: number; 26 | } 27 | 28 | const rawCliOptions: KebabCasedProperties = { 29 | 'dry-run': true, 30 | 'include-file': 'bar.js', 31 | foo: 123 32 | }; 33 | ``` 34 | 35 | @category Change case 36 | @category Template literal 37 | */ 38 | export type KebabCase = DelimiterCase; 39 | -------------------------------------------------------------------------------- /test-d/split.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Split} from '../index'; 3 | 4 | declare function split< 5 | S extends string, 6 | Delimiter extends string, 7 | >(string: S, separator: Delimiter): Split; 8 | 9 | const items = 'foo,bar,baz,waldo'; 10 | 11 | // General use. 12 | expectType<['foo', 'bar', 'baz', 'waldo']>(split(items, ',')); 13 | 14 | // Missing replacement character in original string. 15 | expectType<['foo,bar,baz,waldo']>(split(items, ' ')); 16 | 17 | // Empty string split (every character). 18 | expectType<[ 19 | 'f', 'o', 'o', ',', 'b', 'a', 'r', ',', 20 | 'b', 'a', 'z', ',', 'w', 'a', 'l', 'd', 'o', 21 | ]>(split(items, '')); 22 | 23 | // Split single same character. 24 | expectType<['', '']>(split(' ', ' ')); 25 | 26 | // Split empty string by empty string. 27 | expectType<[]>(split('', '')); 28 | 29 | // Split empty string by any string. 30 | expectType<['']>(split('', ' ')); 31 | -------------------------------------------------------------------------------- /test-d/sum.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Sum} from '../index'; 3 | import type {NegativeInfinity, PositiveInfinity} from '../source/numeric'; 4 | 5 | expectType>(3); 6 | expectType>(8); 7 | expectType>(0); 8 | 9 | expectType>(null! as number); // Note: you can only get `number` for now 10 | 11 | expectType>(null! as PositiveInfinity); 12 | expectType>(null! as PositiveInfinity); 13 | expectType>(null! as NegativeInfinity); 14 | expectType>(null! as NegativeInfinity); 15 | expectType>(null! as number); 16 | 17 | expectType>(null! as number); 18 | expectType>(null! as number); 19 | expectType>(null! as number); 20 | expectType>(null! as number); 21 | -------------------------------------------------------------------------------- /test-d/asyncify.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Asyncify} from '../index'; 3 | 4 | declare function getFooSync(name: string): RegExp; 5 | declare function getFooWithThisArgumentSync(this: Date, name: string): RegExp; 6 | 7 | // Basic usage. 8 | declare const getFooAsync1: Asyncify; 9 | expectType<(name: string) => Promise>(getFooAsync1); 10 | 11 | // Noops with async functions. 12 | declare const getFooAsync2: Asyncify; 13 | expectType(getFooAsync2); 14 | 15 | // Respects `thisArg`. 16 | declare const getFooWithThisArgumentAsync1: Asyncify; 17 | const callResult = getFooWithThisArgumentAsync1.call(new Date(), 'foo'); 18 | expectType>(callResult); 19 | 20 | // @ts-expect-error 21 | // eslint-disable-next-line @typescript-eslint/no-floating-promises 22 | getFooWithThisArgumentAsync1.call('not-date', 'foo'); 23 | -------------------------------------------------------------------------------- /test-d/conditional-except.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {ConditionalExcept, Primitive} from '../index'; 3 | 4 | class Awesome { 5 | name!: string; 6 | successes!: number; 7 | failures!: bigint; 8 | 9 | run(): void { 10 | // Empty 11 | } 12 | } 13 | 14 | type Example = { 15 | a: string; 16 | b?: string | number; 17 | c?: string; 18 | d: Record; 19 | }; 20 | 21 | declare const exampleConditionalExcept: ConditionalExcept; 22 | expectType<{b?: string | number; c?: string; d: Record}>(exampleConditionalExcept); 23 | 24 | declare const awesomeConditionalExcept: ConditionalExcept; 25 | expectType<{run: () => void}>(awesomeConditionalExcept); 26 | 27 | declare const exampleConditionalExceptWithUndefined: ConditionalExcept; 28 | expectType<{b?: string | number; d: Record}>(exampleConditionalExceptWithUndefined); 29 | -------------------------------------------------------------------------------- /test-d/empty-object.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectType} from 'tsd'; 2 | import type {EmptyObject, IsEmptyObject} from '../index'; 3 | 4 | declare let foo: EmptyObject; 5 | 6 | expectAssignable<{}>(foo); 7 | expectAssignable<{}>(foo = {}); 8 | 9 | // @ts-expect-error 10 | foo = []; 11 | // @ts-expect-error 12 | foo = {x: 1}; 13 | // @ts-expect-error 14 | foo = 42; 15 | // @ts-expect-error 16 | foo = null; 17 | // @ts-expect-error 18 | foo.bar = 42; 19 | // @ts-expect-error 20 | foo.bar = {}; 21 | 22 | expectType>(true); 23 | expectType>(true); 24 | 25 | expectType>(false); 26 | expectType>(false); 27 | expectType void>>(false); 28 | 29 | type Union = EmptyObject | {id: number}; 30 | 31 | const bar: Union = {}; 32 | // @ts-expect-error 33 | const _a: unknown = bar.id; 34 | 35 | const baz: Union = {id: 42}; 36 | expectType<{id: number}>(baz); 37 | -------------------------------------------------------------------------------- /test-d/invariant-of.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable} from 'tsd'; 2 | import type {InvariantOf} from '../index'; 3 | 4 | type FooBar = InvariantOf<{ 5 | foo: number; 6 | bar: string; 7 | }>; 8 | 9 | type FooBarBaz = InvariantOf<{ 10 | foo: number; 11 | bar: string; 12 | baz: boolean; 13 | }>; 14 | 15 | // We make an explicit cast so we can test the value. 16 | const fooBar: FooBar = {foo: 123, bar: 'hello'} as FooBar; // eslint-disable-line @typescript-eslint/consistent-type-assertions 17 | const fooBarBaz: FooBarBaz = {foo: 123, bar: 'hello', baz: true} as FooBarBaz; // eslint-disable-line @typescript-eslint/consistent-type-assertions 18 | 19 | // The invariantOf is assignable to Type. 20 | expectAssignable<{ 21 | foo: number; 22 | bar: string; 23 | }>(fooBar); 24 | 25 | expectNotAssignable(fooBar); // Invariance does not accept supertypes. 26 | expectNotAssignable(fooBarBaz); // Invariance does not accept subtypes. 27 | -------------------------------------------------------------------------------- /test-d/simplify-deep.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {SimplifyDeep} from '../index'; 3 | 4 | type Properties1 = { 5 | height: number; 6 | position: { 7 | top: number; 8 | bottom: number; 9 | }; 10 | }; 11 | 12 | type Properties2 = { 13 | width: number; 14 | position: { 15 | left: number; 16 | right: number; 17 | }; 18 | }; 19 | 20 | // Flatten the type output to improve type hints shown in editors. 21 | declare const flattenProperties: { 22 | height: number; 23 | width: number; 24 | position: { 25 | top: number; 26 | bottom: number; 27 | left: number; 28 | right: number; 29 | }; 30 | }; 31 | 32 | expectType>(flattenProperties); 33 | 34 | // Array 35 | type ArrayType = Array<{ 36 | a: string; 37 | }>; 38 | 39 | declare const flattenProperties2: { 40 | arrayType: Array<{ 41 | a: string; 42 | }>; 43 | }; 44 | expectType>(flattenProperties2); 45 | -------------------------------------------------------------------------------- /source/delimiter-cased-properties.d.ts: -------------------------------------------------------------------------------- 1 | import type {DelimiterCase} from './delimiter-case'; 2 | 3 | /** 4 | Convert object properties to delimiter case but not recursively. 5 | 6 | This can be useful when, for example, converting some API types from a different style. 7 | 8 | @see DelimiterCase 9 | @see DelimiterCasedPropertiesDeep 10 | 11 | @example 12 | ``` 13 | import type {DelimiterCasedProperties} from 'type-fest'; 14 | 15 | interface User { 16 | userId: number; 17 | userName: string; 18 | } 19 | 20 | const result: DelimiterCasedProperties = { 21 | 'user-id': 1, 22 | 'user-name': 'Tom', 23 | }; 24 | ``` 25 | 26 | @category Change case 27 | @category Template literal 28 | @category Object 29 | */ 30 | export type DelimiterCasedProperties< 31 | Value, 32 | Delimiter extends string, 33 | > = Value extends Function 34 | ? Value 35 | : Value extends Array 36 | ? Value 37 | : {[K in keyof Value as DelimiterCase]: Value[K]}; 38 | -------------------------------------------------------------------------------- /test-d/arrayable.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Arrayable} from '../index'; 3 | 4 | declare const unknown: unknown; 5 | 6 | expectType>(unknown as string | string[]); 7 | expectType>(unknown as (string | {foo: number}) | Array); 8 | expectType>(unknown as /* never | */ never[]); 9 | expectType>(unknown as string[] | string[][]); 10 | 11 | // Test for issue https://github.com/sindresorhus/type-fest/issues/952 12 | type Item = number; 13 | function castArray1(value: Arrayable): Item[] { 14 | return Array.isArray(value) ? value : [value]; 15 | } 16 | 17 | expectType(unknown as ReturnType); 18 | 19 | function castArray2(value: Arrayable): T[] { 20 | return Array.isArray(value) ? value : [value]; 21 | } 22 | 23 | expectType(castArray2(1)); 24 | expectType(castArray2([1, 2, 3])); 25 | -------------------------------------------------------------------------------- /source/pascal-case.d.ts: -------------------------------------------------------------------------------- 1 | import type {CamelCase, CamelCaseOptions} from './camel-case'; 2 | 3 | /** 4 | Converts a string literal to pascal-case. 5 | 6 | @example 7 | ``` 8 | import type {PascalCase} from 'type-fest'; 9 | 10 | // Simple 11 | 12 | const someVariable: PascalCase<'foo-bar'> = 'FooBar'; 13 | 14 | // Advanced 15 | 16 | type PascalCaseProps = { 17 | [K in keyof T as PascalCase]: T[K] 18 | }; 19 | 20 | interface RawOptions { 21 | 'dry-run': boolean; 22 | 'full_family_name': string; 23 | foo: number; 24 | } 25 | 26 | const dbResult: CamelCasedProperties = { 27 | DryRun: true, 28 | FullFamilyName: 'bar.js', 29 | Foo: 123 30 | }; 31 | ``` 32 | 33 | @category Change case 34 | @category Template literal 35 | */ 36 | export type PascalCase = CamelCase extends string 37 | ? Capitalize> 38 | : CamelCase; 39 | -------------------------------------------------------------------------------- /source/camel-cased-properties.d.ts: -------------------------------------------------------------------------------- 1 | import type {CamelCase, CamelCaseOptions} from './camel-case'; 2 | 3 | /** 4 | Convert object properties to camel case but not recursively. 5 | 6 | This can be useful when, for example, converting some API types from a different style. 7 | 8 | @see CamelCasedPropertiesDeep 9 | @see CamelCase 10 | 11 | @example 12 | ``` 13 | import type {CamelCasedProperties} from 'type-fest'; 14 | 15 | interface User { 16 | UserId: number; 17 | UserName: string; 18 | } 19 | 20 | const result: CamelCasedProperties = { 21 | userId: 1, 22 | userName: 'Tom', 23 | }; 24 | ``` 25 | 26 | @category Change case 27 | @category Template literal 28 | @category Object 29 | */ 30 | export type CamelCasedProperties = Value extends Function 31 | ? Value 32 | : Value extends Array 33 | ? Value 34 | : { 35 | [K in keyof Value as CamelCase]: Value[K]; 36 | }; 37 | -------------------------------------------------------------------------------- /test-d/override-properties.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import {expectTypeOf} from 'expect-type'; 3 | import type {OverrideProperties} from '../source/override-properties'; 4 | 5 | type Foo = { 6 | a: number; 7 | b: string; 8 | }; 9 | 10 | const fixture: OverrideProperties = {a: 1, b: 2}; 11 | expectType<{a: number; b: number}>(fixture); 12 | 13 | // @ts-expect-error 14 | type Bar = OverrideProperties; 15 | 16 | // @ts-expect-error 17 | type Bar = OverrideProperties; 18 | 19 | // Test for https://github.com/sindresorhus/type-fest/issues/858 20 | { // eslint-disable-line no-lone-blocks 21 | type Original = { 22 | foo: string; 23 | bar: string; 24 | }; 25 | 26 | type Modified = { 27 | foo: string | undefined; 28 | bar: string; 29 | }; 30 | 31 | type Final = OverrideProperties; 32 | 33 | expectTypeOf().toMatchTypeOf<{foo: string | undefined; bar: string}>(); 34 | } 35 | -------------------------------------------------------------------------------- /test-d/replace.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Replace} from '../index'; 3 | 4 | declare function replace< 5 | Input extends string, 6 | Search extends string, 7 | Replacement extends string, 8 | >( 9 | input: Input, 10 | search: Search, 11 | replacement: Replacement 12 | ): Replace; 13 | 14 | declare function replaceAll< 15 | Input extends string, 16 | Search extends string, 17 | Replacement extends string, 18 | >( 19 | input: Input, 20 | search: Search, 21 | replacement: Replacement 22 | ): Replace; 23 | 24 | expectType<'hello 🦄'>(replace('hello ?', '?', '🦄')); 25 | expectType<'hello ❓?'>(replace('hello ??', '?', '❓')); 26 | expectType<'10-42-00'>(replaceAll('10:42:00', ':', '-')); 27 | expectType<'userName'>(replaceAll('__userName__', '__', '')); 28 | expectType<'MyCoolTitle'>(replaceAll('My Cool Title', ' ', '')); 29 | expectType<'fobarfobar'>(replaceAll('foobarfoobar', 'ob', 'b')); 30 | -------------------------------------------------------------------------------- /source/pascal-cased-properties.d.ts: -------------------------------------------------------------------------------- 1 | import type {CamelCaseOptions} from './camel-case'; 2 | import type {PascalCase} from './pascal-case'; 3 | 4 | /** 5 | Convert object properties to pascal case but not recursively. 6 | 7 | This can be useful when, for example, converting some API types from a different style. 8 | 9 | @see PascalCase 10 | @see PascalCasedPropertiesDeep 11 | 12 | @example 13 | ``` 14 | import type {PascalCasedProperties} from 'type-fest'; 15 | 16 | interface User { 17 | userId: number; 18 | userName: string; 19 | } 20 | 21 | const result: PascalCasedProperties = { 22 | UserId: 1, 23 | UserName: 'Tom', 24 | }; 25 | ``` 26 | 27 | @category Change case 28 | @category Template literal 29 | @category Object 30 | */ 31 | export type PascalCasedProperties = Value extends Function 32 | ? Value 33 | : Value extends Array 34 | ? Value 35 | : {[K in keyof Value as PascalCase]: Value[K]}; 36 | -------------------------------------------------------------------------------- /test-d/less-than.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {LessThan} from '../index'; 3 | import type {NegativeInfinity, PositiveInfinity} from '../source/numeric'; 4 | 5 | declare const never: never; 6 | 7 | expectType>(true); 8 | expectType>(false); 9 | expectType>(false); 10 | expectType>(false); 11 | expectType>(false); 12 | expectType>(false); 13 | expectType>(false); 14 | expectType>(never); 15 | expectType>(false); 16 | expectType>(false); 17 | expectType>(true); 18 | expectType>(false); 19 | expectType>(false); 20 | expectType>(false); 21 | expectType>(false); 22 | expectType>(false); 23 | -------------------------------------------------------------------------------- /source/is-any.d.ts: -------------------------------------------------------------------------------- 1 | // Can eventually be replaced with the built-in once this library supports 2 | // TS5.4+ only. Tracked in https://github.com/sindresorhus/type-fest/issues/848 3 | type NoInfer = T extends infer U ? U : never; 4 | 5 | /** 6 | Returns a boolean for whether the given type is `any`. 7 | 8 | @link https://stackoverflow.com/a/49928360/1490091 9 | 10 | Useful in type utilities, such as disallowing `any`s to be passed to a function. 11 | 12 | @example 13 | ``` 14 | import type {IsAny} from 'type-fest'; 15 | 16 | const typedObject = {a: 1, b: 2} as const; 17 | const anyObject: any = {a: 1, b: 2}; 18 | 19 | function get extends true ? {} : Record), K extends keyof O = keyof O>(obj: O, key: K) { 20 | return obj[key]; 21 | } 22 | 23 | const typedA = get(typedObject, 'a'); 24 | //=> 1 25 | 26 | const anyA = get(anyObject, 'a'); 27 | //=> any 28 | ``` 29 | 30 | @category Type Guard 31 | @category Utilities 32 | */ 33 | export type IsAny = 0 extends 1 & NoInfer ? true : false; 34 | -------------------------------------------------------------------------------- /source/require-at-least-one.d.ts: -------------------------------------------------------------------------------- 1 | import type {Except} from './except'; 2 | 3 | /** 4 | Create a type that requires at least one of the given keys. The remaining keys are kept as is. 5 | 6 | @example 7 | ``` 8 | import type {RequireAtLeastOne} from 'type-fest'; 9 | 10 | type Responder = { 11 | text?: () => string; 12 | json?: () => string; 13 | secure?: boolean; 14 | }; 15 | 16 | const responder: RequireAtLeastOne = { 17 | json: () => '{"message": "ok"}', 18 | secure: true 19 | }; 20 | ``` 21 | 22 | @category Object 23 | */ 24 | export type RequireAtLeastOne< 25 | ObjectType, 26 | KeysType extends keyof ObjectType = keyof ObjectType, 27 | > = { 28 | // For each `Key` in `KeysType` make a mapped type: 29 | [Key in KeysType]-?: Required> & // 1. Make `Key`'s type required 30 | // 2. Make all other keys in `KeysType` optional 31 | Partial>>; 32 | }[KeysType] & 33 | // 3. Add the remaining keys not in `KeysType` 34 | Except; 35 | -------------------------------------------------------------------------------- /test-d/literal-to-primitive-deep.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsEqual, LiteralToPrimitiveDeep} from '../index'; 3 | 4 | type LiteralObject = { 5 | a: string; 6 | b: number; 7 | c: boolean; 8 | d: { 9 | e: bigint; 10 | f: symbol; 11 | g: { 12 | h: string[]; 13 | i: { 14 | j: boolean; 15 | k: { 16 | l: 1; 17 | m: 'hello'; 18 | o: [1, 2, 3]; 19 | p: ['a', 'b', 'c']; 20 | q: [1, 'a', true]; 21 | }; 22 | }; 23 | }; 24 | }; 25 | }; 26 | 27 | type PrimitiveObject = { 28 | a: string; 29 | b: number; 30 | c: boolean; 31 | d: { 32 | e: bigint; 33 | f: symbol; 34 | g: { 35 | h: string[]; 36 | i: { 37 | j: boolean; 38 | k: { 39 | l: number; 40 | m: string; 41 | o: number[]; 42 | p: string[]; 43 | q: Array; 44 | }; 45 | }; 46 | }; 47 | }; 48 | }; 49 | 50 | const typeEqual: IsEqual< 51 | LiteralToPrimitiveDeep, 52 | PrimitiveObject 53 | > = true; 54 | expectType(typeEqual); 55 | -------------------------------------------------------------------------------- /source/value-of.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Create a union of the given object's values, and optionally specify which keys to get the values from. 3 | 4 | Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/31438) if you want to have this type as a built-in in TypeScript. 5 | 6 | @example 7 | ``` 8 | // data.json 9 | { 10 | 'foo': 1, 11 | 'bar': 2, 12 | 'biz': 3 13 | } 14 | 15 | // main.ts 16 | import type {ValueOf} from 'type-fest'; 17 | import data = require('./data.json'); 18 | 19 | export function getData(name: string): ValueOf { 20 | return data[name]; 21 | } 22 | 23 | export function onlyBar(name: string): ValueOf { 24 | return data[name]; 25 | } 26 | 27 | // file.ts 28 | import {getData, onlyBar} from './main'; 29 | 30 | getData('foo'); 31 | //=> 1 32 | 33 | onlyBar('foo'); 34 | //=> TypeError ... 35 | 36 | onlyBar('bar'); 37 | //=> 2 38 | ``` 39 | 40 | @category Object 41 | */ 42 | export type ValueOf = ObjectType[ValueType]; 43 | -------------------------------------------------------------------------------- /test-d/screaming-snake-case.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {ScreamingSnakeCase} from '../index'; 3 | 4 | const screamingSnakeFromCamel: ScreamingSnakeCase<'fooBar'> = 'FOO_BAR'; 5 | expectType<'FOO_BAR'>(screamingSnakeFromCamel); 6 | 7 | const screamingSnakeFromKebab: ScreamingSnakeCase<'foo-bar'> = 'FOO_BAR'; 8 | expectType<'FOO_BAR'>(screamingSnakeFromKebab); 9 | 10 | const screamingSnakeFromSpace: ScreamingSnakeCase<'foo bar'> = 'FOO_BAR'; 11 | expectType<'FOO_BAR'>(screamingSnakeFromSpace); 12 | 13 | const screamingSnakeFromSnake: ScreamingSnakeCase<'foo_bar'> = 'FOO_BAR'; 14 | expectType<'FOO_BAR'>(screamingSnakeFromSnake); 15 | 16 | const screamingSnakeFromScreamingSnake: ScreamingSnakeCase<'FOO_BAR'> = 'FOO_BAR'; 17 | expectType<'FOO_BAR'>(screamingSnakeFromScreamingSnake); 18 | 19 | const noScreamingSnakeFromMono: ScreamingSnakeCase<'foobar'> = 'FOOBAR'; 20 | expectType<'FOOBAR'>(noScreamingSnakeFromMono); 21 | 22 | const nonStringFromNonString: ScreamingSnakeCase<[]> = []; 23 | expectType<[]>(nonStringFromNonString); 24 | -------------------------------------------------------------------------------- /test-d/camel-cased-properties.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {CamelCasedProperties} from '../index'; 3 | 4 | declare const foo: CamelCasedProperties<{A: number; B: {C: string}}>; 5 | expectType<{a: number; b: {C: string}}>(foo); 6 | 7 | declare const bar: CamelCasedProperties>; 8 | expectType>(bar); 9 | 10 | declare const fooBar: CamelCasedProperties<() => {a: string}>; 11 | expectType<() => {a: string}>(fooBar); 12 | 13 | declare const baz: CamelCasedProperties<{fooBAR: number; BARFoo: string}>; 14 | expectType<{fooBAR: number; bARFoo: string}>(baz); 15 | 16 | declare const biz: CamelCasedProperties<{fooBAR: number; BARFoo: string}, {preserveConsecutiveUppercase: false}>; 17 | expectType<{fooBar: number; barFoo: string}>(biz); 18 | 19 | // Verify example 20 | type User = { 21 | UserId: number; 22 | UserName: string; 23 | }; 24 | 25 | const result: CamelCasedProperties = { 26 | userId: 1, 27 | userName: 'Tom', 28 | }; 29 | expectType>(result); 30 | -------------------------------------------------------------------------------- /source/required-keys-of.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Extract all required keys from the given type. 3 | 4 | This is useful when you want to create a new type that contains different type values for the required keys only or use the list of keys for validation purposes, etc... 5 | 6 | @example 7 | ``` 8 | import type {RequiredKeysOf} from 'type-fest'; 9 | 10 | declare function createValidation = RequiredKeysOf>(field: Key, validator: (value: Entity[Key]) => boolean): ValidatorFn; 11 | 12 | interface User { 13 | name: string; 14 | surname: string; 15 | 16 | luckyNumber?: number; 17 | } 18 | 19 | const validator1 = createValidation('name', value => value.length < 25); 20 | const validator2 = createValidation('surname', value => value.length < 25); 21 | ``` 22 | 23 | @category Utilities 24 | */ 25 | export type RequiredKeysOf = Exclude<{ 26 | [Key in keyof BaseType]: BaseType extends Record 27 | ? Key 28 | : never 29 | }[keyof BaseType], undefined>; 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | /// "extends": "@sindresorhus/tsconfig", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "noUnusedLocals": false, // Allow unused variables in test-d/*.ts files 6 | "target": "ES2021", // Node.js 16 7 | "lib": [ 8 | "ES2021", 9 | ], 10 | "types": [], // Ensures no @types/ are unintentionally included 11 | "exactOptionalPropertyTypes": true, 12 | "skipLibCheck": false, // Ensures .d.ts files are checked: https://github.com/sindresorhus/tsconfig/issues/15 13 | 14 | // Compatibility 15 | "module": "commonjs", 16 | "moduleResolution": "node", 17 | 18 | // TODO: Use the reusable tsconfig again when targeting ESM. 19 | // From https://github.com/sindresorhus/tsconfig/blob/main/tsconfig.json 20 | "strict": true, 21 | "noImplicitReturns": true, 22 | "noImplicitOverride": true, 23 | "noUnusedParameters": true, 24 | "noFallthroughCasesInSwitch": true, 25 | // "noUncheckedIndexedAccess": true, // TODO: Enable. 26 | "noPropertyAccessFromIndexSignature": true, 27 | "useDefineForClassFields": true, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test-d/greater-than.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {GreaterThan} from '../index'; 3 | import type {NegativeInfinity, PositiveInfinity} from '../source/numeric'; 4 | 5 | declare const never: never; 6 | 7 | expectType>(false); 8 | expectType>(true); 9 | expectType>(true); 10 | expectType>(true); 11 | expectType>(false); 12 | expectType>(false); 13 | expectType>(true); 14 | expectType>(never); 15 | 16 | expectType>(true); 17 | expectType>(true); 18 | expectType>(false); 19 | expectType>(true); 20 | expectType>(true); 21 | expectType>(false); 22 | expectType>(false); 23 | expectType>(true); 24 | -------------------------------------------------------------------------------- /source/literal-to-primitive.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Given a [literal type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) return the {@link Primitive | primitive type} it belongs to, or `never` if it's not a primitive. 3 | 4 | Use-case: Working with generic types that may be literal types. 5 | 6 | @example 7 | ``` 8 | import type {LiteralToPrimitive} from 'type-fest'; 9 | 10 | // No overloads needed to get the correct return type 11 | function plus(x: T, y: T): LiteralToPrimitive { 12 | return x + (y as any); 13 | } 14 | 15 | plus('a', 'b'); // string 16 | plus(1, 2); // number 17 | plus(1n, 2n); // bigint 18 | ``` 19 | 20 | @category Type 21 | */ 22 | export type LiteralToPrimitive = T extends number 23 | ? number 24 | : T extends bigint 25 | ? bigint 26 | : T extends string 27 | ? string 28 | : T extends boolean 29 | ? boolean 30 | : T extends symbol 31 | ? symbol 32 | : T extends null 33 | ? null 34 | : T extends undefined 35 | ? undefined 36 | : never; 37 | -------------------------------------------------------------------------------- /source/optional-keys-of.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Extract all optional keys from the given type. 3 | 4 | This is useful when you want to create a new type that contains different type values for the optional keys only. 5 | 6 | @example 7 | ``` 8 | import type {OptionalKeysOf, Except} from 'type-fest'; 9 | 10 | interface User { 11 | name: string; 12 | surname: string; 13 | 14 | luckyNumber?: number; 15 | } 16 | 17 | const REMOVE_FIELD = Symbol('remove field symbol'); 18 | type UpdateOperation = Except, OptionalKeysOf> & { 19 | [Key in OptionalKeysOf]?: Entity[Key] | typeof REMOVE_FIELD; 20 | }; 21 | 22 | const update1: UpdateOperation = { 23 | name: 'Alice' 24 | }; 25 | 26 | const update2: UpdateOperation = { 27 | name: 'Bob', 28 | luckyNumber: REMOVE_FIELD 29 | }; 30 | ``` 31 | 32 | @category Utilities 33 | */ 34 | export type OptionalKeysOf = Exclude<{ 35 | [Key in keyof BaseType]: BaseType extends Record 36 | ? never 37 | : Key 38 | }[keyof BaseType], undefined>; 39 | -------------------------------------------------------------------------------- /source/require-one-or-none.d.ts: -------------------------------------------------------------------------------- 1 | import type {RequireExactlyOne} from './require-exactly-one'; 2 | import type {RequireNone} from './internal'; 3 | 4 | /** 5 | Create a type that requires exactly one of the given keys and disallows more, or none of the given keys. The remaining keys are kept as is. 6 | 7 | @example 8 | ``` 9 | import type {RequireOneOrNone} from 'type-fest'; 10 | 11 | type Responder = RequireOneOrNone<{ 12 | text: () => string; 13 | json: () => string; 14 | secure: boolean; 15 | }, 'text' | 'json'>; 16 | 17 | const responder1: Responder = { 18 | secure: true 19 | }; 20 | 21 | const responder2: Responder = { 22 | text: () => '{"message": "hi"}', 23 | secure: true 24 | }; 25 | 26 | const responder3: Responder = { 27 | json: () => '{"message": "ok"}', 28 | secure: true 29 | }; 30 | ``` 31 | 32 | @category Object 33 | */ 34 | export type RequireOneOrNone = ( 35 | | RequireExactlyOne 36 | | RequireNone 37 | ) & Omit; // Ignore unspecified keys. 38 | -------------------------------------------------------------------------------- /source/screaming-snake-case.d.ts: -------------------------------------------------------------------------------- 1 | import type {SplitIncludingDelimiters} from './delimiter-case'; 2 | import type {SnakeCase} from './snake-case'; 3 | import type {Includes} from './includes'; 4 | 5 | /** 6 | Returns a boolean for whether the string is screaming snake case. 7 | */ 8 | type IsScreamingSnakeCase = Value extends Uppercase 9 | ? Includes, '_'>, '_'> extends true 10 | ? true 11 | : false 12 | : false; 13 | 14 | /** 15 | Convert a string literal to screaming-snake-case. 16 | 17 | This can be useful when, for example, converting a camel-cased object property to a screaming-snake-cased SQL column name. 18 | 19 | @example 20 | ``` 21 | import type {ScreamingSnakeCase} from 'type-fest'; 22 | 23 | const someVariable: ScreamingSnakeCase<'fooBar'> = 'FOO_BAR'; 24 | ``` 25 | 26 | @category Change case 27 | @category Template literal 28 | */ 29 | export type ScreamingSnakeCase = Value extends string 30 | ? IsScreamingSnakeCase extends true 31 | ? Value 32 | : Uppercase> 33 | : Value; 34 | -------------------------------------------------------------------------------- /test-d/jsonifiable.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable} from 'tsd'; 2 | import type {Jsonifiable} from '..'; 3 | 4 | expectAssignable(1); 5 | expectAssignable(''); 6 | expectAssignable(null); 7 | expectAssignable(new Date()); 8 | expectAssignable({a: new Date()}); 9 | expectAssignable([new Date()]); 10 | expectAssignable({a: undefined}); 11 | expectAssignable([1, 2, 3] as const); 12 | expectAssignable({a: new Date()} as const); 13 | expectAssignable({a: {deeply: {nested: {toJsonObject: new Date()}}}}); 14 | expectAssignable({toJSON: () => new Date()}); 15 | expectAssignable({ 16 | toJSON() { 17 | return { 18 | foo: { 19 | toJSON() { 20 | return {bar: 'bar'}; 21 | }, 22 | }, 23 | }; 24 | }, 25 | }); 26 | 27 | expectNotAssignable(undefined); 28 | expectNotAssignable(new Map()); 29 | expectNotAssignable({a: new Map()}); 30 | expectNotAssignable([new Map()]); 31 | -------------------------------------------------------------------------------- /source/snake-cased-properties-deep.d.ts: -------------------------------------------------------------------------------- 1 | import type {DelimiterCasedPropertiesDeep} from './delimiter-cased-properties-deep'; 2 | 3 | /** 4 | Convert object properties to snake case recursively. 5 | 6 | This can be useful when, for example, converting some API types from a different style. 7 | 8 | @see SnakeCase 9 | @see SnakeCasedProperties 10 | 11 | @example 12 | ``` 13 | import type {SnakeCasedPropertiesDeep} from 'type-fest'; 14 | 15 | interface User { 16 | userId: number; 17 | userName: string; 18 | } 19 | 20 | interface UserWithFriends { 21 | userInfo: User; 22 | userFriends: User[]; 23 | } 24 | 25 | const result: SnakeCasedPropertiesDeep = { 26 | user_info: { 27 | user_id: 1, 28 | user_name: 'Tom', 29 | }, 30 | user_friends: [ 31 | { 32 | user_id: 2, 33 | user_name: 'Jerry', 34 | }, 35 | { 36 | user_id: 3, 37 | user_name: 'Spike', 38 | }, 39 | ], 40 | }; 41 | ``` 42 | 43 | @category Change case 44 | @category Template literal 45 | @category Object 46 | */ 47 | export type SnakeCasedPropertiesDeep = DelimiterCasedPropertiesDeep; 48 | -------------------------------------------------------------------------------- /source/non-empty-object.d.ts: -------------------------------------------------------------------------------- 1 | import type {HasRequiredKeys} from './has-required-keys'; 2 | import type {RequireAtLeastOne} from './require-at-least-one'; 3 | 4 | /** 5 | Represents an object with at least 1 non-optional key. 6 | 7 | This is useful when you need an object where all keys are optional, but there must be at least 1 key. 8 | 9 | @example 10 | ``` 11 | import type {NonEmptyObject} from 'type-fest'; 12 | 13 | type User = { 14 | name: string; 15 | surname: string; 16 | id: number; 17 | }; 18 | 19 | type UpdateRequest = NonEmptyObject>; 20 | 21 | const update1: UpdateRequest = { 22 | name: 'Alice', 23 | surname: 'Acme', 24 | }; 25 | 26 | // At least 1 key is required, therefore this will report a 2322 error: 27 | // Type '{}' is not assignable to type 'UpdateRequest' 28 | const update2: UpdateRequest = {}; 29 | ``` 30 | 31 | @see Use `IsEmptyObject` to check whether an object is empty. 32 | 33 | @category Object 34 | */ 35 | export type NonEmptyObject = HasRequiredKeys extends true ? T : RequireAtLeastOne; 36 | -------------------------------------------------------------------------------- /source/kebab-cased-properties-deep.d.ts: -------------------------------------------------------------------------------- 1 | import type {DelimiterCasedPropertiesDeep} from './delimiter-cased-properties-deep'; 2 | 3 | /** 4 | Convert object properties to kebab case recursively. 5 | 6 | This can be useful when, for example, converting some API types from a different style. 7 | 8 | @see KebabCase 9 | @see KebabCasedProperties 10 | 11 | @example 12 | ``` 13 | import type [KebabCasedPropertiesDeep] from 'type-fest'; 14 | 15 | interface User { 16 | userId: number; 17 | userName: string; 18 | } 19 | 20 | interface UserWithFriends { 21 | userInfo: User; 22 | userFriends: User[]; 23 | } 24 | 25 | const result: KebabCasedPropertiesDeep = { 26 | 'user-info': { 27 | 'user-id': 1, 28 | 'user-name': 'Tom', 29 | }, 30 | 'user-friends': [ 31 | { 32 | 'user-id': 2, 33 | 'user-name': 'Jerry', 34 | }, 35 | { 36 | 'user-id': 3, 37 | 'user-name': 'Spike', 38 | }, 39 | ], 40 | }; 41 | ``` 42 | 43 | @category Change case 44 | @category Template literal 45 | @category Object 46 | */ 47 | export type KebabCasedPropertiesDeep = DelimiterCasedPropertiesDeep; 48 | -------------------------------------------------------------------------------- /test-d/multidimensional-readonly-array.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {MultidimensionalReadonlyArray} from '../index'; 3 | 4 | function createArray(dimensions: T): MultidimensionalReadonlyArray { 5 | const root: unknown[] = []; 6 | 7 | let array = root; 8 | for (let dimension = 1; dimension < dimensions; ++dimension) { 9 | array[0] = []; 10 | if (dimension < dimensions - 1) { 11 | array = array[0] as unknown[]; 12 | } else { 13 | array[0] = '42'; 14 | } 15 | } 16 | 17 | return root as MultidimensionalReadonlyArray as MultidimensionalReadonlyArray; 18 | } 19 | 20 | const a: MultidimensionalReadonlyArray = []; 21 | const b: MultidimensionalReadonlyArray = []; 22 | const c = createArray(2); 23 | 24 | const answer = c[0][0]; // '42' 25 | 26 | type RecursiveArray = ReadonlyArray>; 27 | 28 | expectType(answer); 29 | 30 | expectType>>(a); 31 | expectType>(b); 32 | expectType>(c); 33 | -------------------------------------------------------------------------------- /test-d/omit-index-signature.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {OmitIndexSignature} from '../index'; 3 | 4 | type ExampleInterface = { 5 | // These index signatures will be removed. 6 | [x: string]: any; 7 | [x: number]: any; 8 | [x: symbol]: any; 9 | [x: `head-${string}`]: string; 10 | [x: `${string}-tail`]: string; 11 | [x: `head-${string}-tail`]: string; 12 | [x: `${bigint}`]: string; 13 | [x: `embedded-${number}`]: string; 14 | 15 | // These explicitly defined keys will remain. 16 | foo: 'bar'; 17 | qux?: 'baz'; 18 | }; 19 | 20 | type MappedType = { 21 | [Key in keyof ObjectType]: { 22 | key: Key; 23 | value: Exclude; 24 | }; 25 | }; 26 | 27 | declare const exampleInterfaceKnownKeys: OmitIndexSignature; 28 | expectType<{ 29 | foo: 'bar'; 30 | qux?: 'baz'; 31 | }>(exampleInterfaceKnownKeys); 32 | 33 | declare const exampleMappedTypeKnownKeys: OmitIndexSignature< 34 | MappedType 35 | >; 36 | expectType<{ 37 | foo: {key: 'foo'; value: 'bar'}; 38 | qux?: {key: 'qux'; value: 'baz'}; 39 | }>(exampleMappedTypeKnownKeys); 40 | -------------------------------------------------------------------------------- /source/is-equal.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Returns a boolean for whether the two given types are equal. 3 | 4 | @link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650 5 | @link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796 6 | 7 | Use-cases: 8 | - If you want to make a conditional branch based on the result of a comparison of two types. 9 | 10 | @example 11 | ``` 12 | import type {IsEqual} from 'type-fest'; 13 | 14 | // This type returns a boolean for whether the given array includes the given item. 15 | // `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal. 16 | type Includes = 17 | Value extends readonly [Value[0], ...infer rest] 18 | ? IsEqual extends true 19 | ? true 20 | : Includes 21 | : false; 22 | ``` 23 | 24 | @category Type Guard 25 | @category Utilities 26 | */ 27 | export type IsEqual = 28 | (() => G extends A & G | G ? 1 : 2) extends 29 | (() => G extends B & G | G ? 1 : 2) 30 | ? true 31 | : false; 32 | -------------------------------------------------------------------------------- /test-d/snake-cased-properties-deep.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {SnakeCasedPropertiesDeep} from '../index'; 3 | 4 | declare const foo: SnakeCasedPropertiesDeep<{helloWorld: {fooBar: string}}>; 5 | expectType<{hello_world: {foo_bar: string}}>(foo); 6 | 7 | declare const bar: SnakeCasedPropertiesDeep>; 8 | expectType>(bar); 9 | 10 | // Verify example 11 | type User = { 12 | userId: number; 13 | userName: string; 14 | date: Date; 15 | regExp: RegExp; 16 | }; 17 | 18 | type UserWithFriends = { 19 | userInfo: User; 20 | userFriends: User[]; 21 | }; 22 | 23 | const result: SnakeCasedPropertiesDeep = { 24 | user_info: { 25 | user_id: 1, 26 | user_name: 'Tom', 27 | date: new Date(), 28 | reg_exp: /.*/, 29 | }, 30 | user_friends: [ 31 | { 32 | user_id: 2, 33 | user_name: 'Jerry', 34 | date: new Date(), 35 | reg_exp: /.*/, 36 | }, 37 | { 38 | user_id: 3, 39 | user_name: 'Spike', 40 | date: new Date(), 41 | reg_exp: /.*/, 42 | }, 43 | ], 44 | }; 45 | expectType>(result); 46 | -------------------------------------------------------------------------------- /license-mit: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (https://sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /test-d/less-than-or-equal.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {LessThanOrEqual} from '../index'; 3 | import type {NegativeInfinity, PositiveInfinity} from '../source/numeric'; 4 | 5 | declare const never: never; 6 | 7 | expectType>(true); 8 | expectType>(false); 9 | expectType>(false); 10 | expectType>(false); 11 | expectType>(true); 12 | expectType>(true); 13 | expectType>(false); 14 | expectType>(never); 15 | expectType>(false); 16 | expectType>(false); 17 | expectType>(true); 18 | expectType>(false); 19 | expectType>(false); 20 | expectType>(true); 21 | expectType>(true); 22 | expectType>(false); 23 | -------------------------------------------------------------------------------- /source/string-repeat.d.ts: -------------------------------------------------------------------------------- 1 | import type {IsNegative} from './numeric'; 2 | import type {Subtract} from './subtract'; 3 | 4 | /** 5 | Returns a new string which contains the specified number of copies of a given string, just like `String#repeat()`. 6 | 7 | @example 8 | ``` 9 | import {StringRepeat} from 'type-fest'; 10 | 11 | declare function stringRepeat< 12 | Input extends string, 13 | Count extends number 14 | >(input: Input, count: Count): StringRepeat; 15 | 16 | // The return type is the exact string literal, not just `string`. 17 | 18 | stringRepeat('foo', 2); 19 | //=> 'foofoo' 20 | 21 | stringRepeat('=', 3); 22 | //=> '===' 23 | ``` 24 | 25 | @category String 26 | @category Template literal 27 | */ 28 | export type StringRepeat< 29 | Input extends string, 30 | Count extends number, 31 | > = number extends Count 32 | ? Input extends '' 33 | ? '' 34 | : string 35 | : IsNegative extends true 36 | ? never 37 | : Count extends 0 38 | ? '' 39 | : string extends Input 40 | ? string 41 | : StringRepeat> extends infer R extends string 42 | ? `${Input}${R}` 43 | : never; 44 | -------------------------------------------------------------------------------- /test-d/require-one-or-none.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable} from 'tsd'; 2 | import type {RequireOneOrNone} from '../index'; 3 | 4 | type OneAtMost = RequireOneOrNone>; 5 | 6 | expectAssignable({}); 7 | expectAssignable({foo: true}); 8 | expectAssignable({bar: true}); 9 | expectAssignable({baz: true}); 10 | 11 | expectNotAssignable({foo: true, bar: true}); 12 | expectNotAssignable({foo: true, baz: true}); 13 | expectNotAssignable({bar: true, baz: true}); 14 | expectNotAssignable({foo: true, bar: true, baz: true}); 15 | 16 | // 'foo' always required 17 | type OneOrTwo = RequireOneOrNone, 'bar' | 'baz'>; 18 | 19 | expectAssignable({foo: true}); 20 | expectAssignable({foo: true, bar: true}); 21 | expectAssignable({foo: true, baz: true}); 22 | 23 | expectNotAssignable({}); 24 | expectNotAssignable({bar: true}); 25 | expectNotAssignable({baz: true}); 26 | expectNotAssignable({foo: true, bar: true, baz: true}); 27 | -------------------------------------------------------------------------------- /test-d/last-array-element.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {LastArrayElement} from '../index'; 3 | 4 | declare function lastOf(array: V): LastArrayElement; 5 | const array: ['foo', 2, 'bar'] = ['foo', 2, 'bar']; 6 | const mixedArray: ['bar', 'foo', 2] = ['bar', 'foo', 2]; 7 | 8 | expectType<'bar'>(lastOf(array)); 9 | expectType<2>(lastOf(mixedArray)); 10 | expectType(lastOf(['a', 'b', 'c'])); 11 | expectType(lastOf(['a', 'b', 1])); 12 | expectType<1>(lastOf(['a', 'b', 1] as const)); 13 | 14 | declare const leadingSpreadTuple: [...string[], object, number]; 15 | expectType(lastOf(leadingSpreadTuple)); 16 | 17 | declare const trailingSpreadTuple1: [string, ...number[]]; 18 | expectType(lastOf(trailingSpreadTuple1)); 19 | 20 | declare const trailingSpreadTuple2: [string, boolean, ...number[]]; 21 | expectType(lastOf(trailingSpreadTuple2)); 22 | 23 | // eslint-disable-next-line @typescript-eslint/array-type 24 | declare const trailingSpreadTuple3: ['foo', true, ...(1 | '2')[]]; 25 | expectType(lastOf(trailingSpreadTuple3)); 26 | -------------------------------------------------------------------------------- /test-d/kebab-cased-properties-deep.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {KebabCasedPropertiesDeep} from '../index'; 3 | 4 | declare const foo: KebabCasedPropertiesDeep<{helloWorld: {fooBar: string}}>; 5 | expectType<{'hello-world': {'foo-bar': string}}>(foo); 6 | 7 | declare const bar: KebabCasedPropertiesDeep>; 8 | expectType>(bar); 9 | 10 | // Verify example 11 | type User = { 12 | userId: number; 13 | userName: string; 14 | date: Date; 15 | regExp: RegExp; 16 | }; 17 | 18 | type UserWithFriends = { 19 | userInfo: User; 20 | userFriends: User[]; 21 | }; 22 | 23 | const result: KebabCasedPropertiesDeep = { 24 | 'user-info': { 25 | 'user-id': 1, 26 | 'user-name': 'Tom', 27 | date: new Date(), 28 | 'reg-exp': /.*/, 29 | }, 30 | 'user-friends': [ 31 | { 32 | 'user-id': 2, 33 | 'user-name': 'Jerry', 34 | date: new Date(), 35 | 'reg-exp': /.*/, 36 | }, 37 | { 38 | 'user-id': 3, 39 | 'user-name': 'Spike', 40 | date: new Date(), 41 | 'reg-exp': /.*/, 42 | }, 43 | ], 44 | }; 45 | expectType>(result); 46 | -------------------------------------------------------------------------------- /test-d/tuple-to-union.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotType, expectType} from 'tsd'; 2 | import type {TupleToUnion} from '../index'; 3 | 4 | const options = ['a', 'b', 'c'] as const; 5 | type Options = TupleToUnion; 6 | 7 | const a: Options = 'a'; 8 | expectAssignable(a); 9 | expectType<'a'>(a); 10 | expectNotType<'b'>(a); 11 | expectNotType<'c'>(a); 12 | 13 | const b: Options = 'b'; 14 | expectAssignable(b); 15 | expectNotType<'a'>(b); 16 | expectType<'b'>(b); 17 | expectNotType<'c'>(b); 18 | 19 | const c: Options = 'c'; 20 | expectAssignable(c); 21 | expectNotType<'a'>(c); 22 | expectNotType<'b'>(c); 23 | expectType<'c'>(c); 24 | 25 | declare const notAnArray: TupleToUnion<[]>; 26 | expectType(notAnArray); 27 | 28 | declare const worksWithArrays: TupleToUnion>; 29 | expectType(worksWithArrays); 30 | 31 | declare const resolvesToNeverForNonArrays: TupleToUnion; 32 | expectType(resolvesToNeverForNonArrays); 33 | 34 | declare const infiniteRestArguments: TupleToUnion<[string, ...number[]]>; 35 | expectType(infiniteRestArguments); 36 | -------------------------------------------------------------------------------- /source/conditional-pick.d.ts: -------------------------------------------------------------------------------- 1 | import type {ConditionalKeys} from './conditional-keys'; 2 | 3 | /** 4 | Pick keys from the shape that matches the given `Condition`. 5 | 6 | This is useful when you want to create a new type from a specific subset of an existing type. For example, you might want to pick all the primitive properties from a class and form a new automatically derived type. 7 | 8 | @example 9 | ``` 10 | import type {Primitive, ConditionalPick} from 'type-fest'; 11 | 12 | class Awesome { 13 | name: string; 14 | successes: number; 15 | failures: bigint; 16 | 17 | run() {} 18 | } 19 | 20 | type PickPrimitivesFromAwesome = ConditionalPick; 21 | //=> {name: string; successes: number; failures: bigint} 22 | ``` 23 | 24 | @example 25 | ``` 26 | import type {ConditionalPick} from 'type-fest'; 27 | 28 | interface Example { 29 | a: string; 30 | b: string | number; 31 | c: () => void; 32 | d: {}; 33 | } 34 | 35 | type StringKeysOnly = ConditionalPick; 36 | //=> {a: string} 37 | ``` 38 | 39 | @category Object 40 | */ 41 | export type ConditionalPick = Pick< 42 | Base, 43 | ConditionalKeys 44 | >; 45 | -------------------------------------------------------------------------------- /test-d/subtract.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {Subtract} from '../index'; 3 | import type {NegativeInfinity, PositiveInfinity} from '../source/numeric'; 4 | 5 | expectType>(12); 6 | expectType>(0); 7 | expectType>(2); 8 | 9 | expectType>(null! as number); // Note: you can only get `number` for now 10 | 11 | expectType>(null! as PositiveInfinity); 12 | expectType>(null! as NegativeInfinity); 13 | expectType>(null! as NegativeInfinity); 14 | expectType>(null! as PositiveInfinity); 15 | expectType>(null! as NegativeInfinity); 16 | expectType>(null! as number); 17 | expectType>(null! as number); 18 | 19 | expectType>(null! as number); 20 | expectType>(null! as number); 21 | expectType>(null! as number); 22 | expectType>(null! as number); 23 | -------------------------------------------------------------------------------- /test-d/greater-than-or-equal.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {GreaterThanOrEqual} from '../index'; 3 | import type {NegativeInfinity, PositiveInfinity} from '../source/numeric'; 4 | 5 | declare const never: never; 6 | 7 | expectType>(false); 8 | expectType>(true); 9 | expectType>(true); 10 | expectType>(true); 11 | expectType>(true); 12 | expectType>(true); 13 | expectType>(true); 14 | expectType>(never); 15 | 16 | expectType>(true); 17 | expectType>(true); 18 | expectType>(false); 19 | expectType>(true); 20 | expectType>(true); 21 | expectType>(true); 22 | expectType>(true); 23 | expectType>(true); 24 | -------------------------------------------------------------------------------- /source/jsonifiable.d.ts: -------------------------------------------------------------------------------- 1 | import type {JsonPrimitive} from './basic'; 2 | 3 | type JsonifiableObject = {[Key in string]?: Jsonifiable} | {toJSON: () => Jsonifiable}; 4 | type JsonifiableArray = readonly Jsonifiable[]; 5 | 6 | /** 7 | Matches a value that can be losslessly converted to JSON. 8 | 9 | Can be used to type values that you expect to pass to `JSON.stringify`. 10 | 11 | `undefined` is allowed in object fields (for example, `{a?: number}`) as a special case even though `JSON.stringify({a: undefined})` is `{}` because it makes this class more widely useful and checking for undefined-but-present values is likely an anti-pattern. 12 | 13 | @example 14 | ``` 15 | import type {Jsonifiable} from 'type-fest'; 16 | 17 | // @ts-expect-error 18 | const error: Jsonifiable = { 19 | map: new Map([['a', 1]]), 20 | }; 21 | 22 | JSON.stringify(error); 23 | //=> {"map": {}} 24 | 25 | const good: Jsonifiable = { 26 | number: 3, 27 | date: new Date(), 28 | missing: undefined, 29 | } 30 | 31 | JSON.stringify(good); 32 | //=> {"number": 3, "date": "2022-10-17T22:22:35.920Z"} 33 | ``` 34 | 35 | @category JSON 36 | */ 37 | export type Jsonifiable = JsonPrimitive | JsonifiableObject | JsonifiableArray; 38 | -------------------------------------------------------------------------------- /test-d/array-values.ts: -------------------------------------------------------------------------------- 1 | import {expectNotAssignable, expectType, expectAssignable} from 'tsd'; 2 | import type {ArrayValues} from '../index'; 3 | 4 | const values = ['a', 'b', 'c'] as const; 5 | type Values = ArrayValues; 6 | 7 | declare const test: 'a' | 'b' | 'c'; 8 | expectType(test); 9 | 10 | expectAssignable('a'); 11 | expectAssignable('b'); 12 | expectAssignable('c'); 13 | 14 | expectNotAssignable(''); 15 | expectNotAssignable(0); 16 | 17 | type TupleValues = ArrayValues<['1', 2, {c: true}]>; 18 | 19 | declare const testTuple: '1' | 2 | {c: true}; 20 | expectType(testTuple); 21 | 22 | expectAssignable('1'); 23 | expectAssignable(2); 24 | expectAssignable({c: true}); 25 | 26 | expectNotAssignable({}); 27 | expectNotAssignable(1); 28 | expectNotAssignable('2'); 29 | 30 | type AnyStringValues = ArrayValues; 31 | expectAssignable(''); 32 | expectAssignable('123'); 33 | expectNotAssignable(123); 34 | expectNotAssignable(undefined); 35 | expectNotAssignable(null); 36 | -------------------------------------------------------------------------------- /test-d/require-at-least-one.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable} from 'tsd'; 2 | import type {RequireAtLeastOne} from '../index'; 3 | 4 | type SystemMessages = { 5 | default: string; 6 | 7 | macos?: string; 8 | linux?: string; 9 | windows?: string; 10 | 11 | optional?: string; 12 | }; 13 | 14 | type ValidMessages = RequireAtLeastOne; 15 | declare const test: (_: ValidMessages) => void; 16 | 17 | test({macos: 'hey', default: 'hello'}); 18 | test({linux: 'sup', default: 'hello', optional: 'howdy'}); 19 | test({macos: 'hey', linux: 'sup', windows: 'hi', default: 'hello'}); 20 | 21 | // @ts-expect-error 22 | test({}); 23 | // @ts-expect-error 24 | test({macos: 'hey'}); 25 | // @ts-expect-error 26 | test({default: 'hello'}); 27 | 28 | declare const testWithoutKeys: (_: RequireAtLeastOne<{a: number; b: number}>) => void; 29 | 30 | testWithoutKeys({a: 1}); 31 | testWithoutKeys({b: 2}); 32 | testWithoutKeys({a: 1, b: 2}); 33 | 34 | // @ts-expect-error 35 | testWithoutKeys({}); 36 | 37 | type MessageBoard = (messages: M) => string; 38 | 39 | expectAssignable>( 40 | ({macos = '', linux = '🐧', windows = '⊞'}) => 41 | `${linux} + ${windows} = ${macos}`, 42 | ); 43 | -------------------------------------------------------------------------------- /test-d/array-tail.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {ArrayTail} from '../index'; 3 | 4 | declare const getArrayTail: (array: T) => ArrayTail; 5 | 6 | expectType<[]>(getArrayTail([])); 7 | expectType<[]>(getArrayTail(['a'])); 8 | expectType<[]>(getArrayTail(['a', 'b', 'c'])); 9 | 10 | expectType<[]>(getArrayTail([] as const)); 11 | expectType<[]>(getArrayTail(['a'] as const)); 12 | expectType<['b', 'c']>(getArrayTail(['a', 'b', 'c'] as const)); 13 | 14 | // Optional elements tests 15 | expectType<[undefined, 'c']>(getArrayTail(['a', undefined, 'c'] as const)); 16 | 17 | // Mixed optional/required 18 | type MixedArray = [string, undefined?, number?]; 19 | expectType<[undefined?, number?]>(getArrayTail(['hello'] as MixedArray)); 20 | 21 | // Optional numbers 22 | expectType<[undefined, 3]>(getArrayTail([1, undefined, 3] as const)); 23 | 24 | // Complex mixed case 25 | type ComplexArray = [string, boolean, number?, string?]; 26 | expectType<[boolean, number?, string?]>(getArrayTail(['test', false] as ComplexArray)); 27 | 28 | // All optional elements 29 | expectType<['b'?]>([] as ArrayTail<['a'?, 'b'?]>); 30 | 31 | // Union of tuples 32 | expectType<[] | ['b']>([] as ArrayTail<[] | ['a', 'b']>); 33 | -------------------------------------------------------------------------------- /test-d/pascal-cased-properties-deep.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {PascalCasedPropertiesDeep} from '../index'; 3 | 4 | declare const foo: PascalCasedPropertiesDeep<{helloWorld: {fooBar: string}}>; 5 | expectType<{HelloWorld: {FooBar: string}}>(foo); 6 | 7 | declare const fooBar: PascalCasedPropertiesDeep<() => {a: string}>; 8 | expectType<() => {a: string}>(fooBar); 9 | 10 | declare const bar: PascalCasedPropertiesDeep>; 11 | expectType>(bar); 12 | 13 | // Verify example 14 | type User = { 15 | userId: number; 16 | userName: string; 17 | date: Date; 18 | regExp: RegExp; 19 | }; 20 | 21 | type UserWithFriends = { 22 | userInfo: User; 23 | userFriends: User[]; 24 | }; 25 | 26 | const result: PascalCasedPropertiesDeep = { 27 | UserInfo: { 28 | UserId: 1, 29 | UserName: 'Tom', 30 | Date: new Date(), 31 | RegExp: /.*/, 32 | }, 33 | UserFriends: [ 34 | { 35 | UserId: 2, 36 | UserName: 'Jerry', 37 | Date: new Date(), 38 | RegExp: /.*/, 39 | }, 40 | { 41 | UserId: 3, 42 | UserName: 'Spike', 43 | Date: new Date(), 44 | RegExp: /.*/, 45 | }, 46 | ], 47 | }; 48 | expectType>(result); 49 | -------------------------------------------------------------------------------- /test-d/array-splice.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {ArraySplice} from '../index'; 3 | 4 | // Test fixed array 5 | type TestTuple = ['a', 'b', 'c', 'd']; 6 | 7 | declare const tuple0: ArraySplice; 8 | expectType<['a', 'b', 'd']>(tuple0); 9 | 10 | declare const tuple1: ArraySplice; 11 | expectType<['a', 'b', 'e', 'f', 'd']>(tuple1); 12 | 13 | declare const tuple2: ArraySplice; 14 | expectType<['a', 'b', 'e', 'f', 'c', 'd']>(tuple2); 15 | 16 | declare const tuple3: ArraySplice; 17 | expectType<['b', 'c', 'd']>(tuple3); 18 | 19 | declare const tuple4: ArraySplice; 20 | expectType<['e', 'f', 'b', 'c', 'd']>(tuple4); 21 | 22 | // Test variable array 23 | type TestArray = ['a', 'b', 'c', 'd', ...number[]]; 24 | 25 | declare const array0: ArraySplice; 26 | expectType<['a', 'b', 'd', ...number[]]>(array0); 27 | 28 | declare const array1: ArraySplice; 29 | expectType<['a', 'b', 'e', 'f', 'd', ...number[]]>(array1); 30 | 31 | declare const array2: ArraySplice; 32 | expectType<['a', 'b', 'c', 'd', number, number, 'e', 'f', ...number[]]>(array2); 33 | -------------------------------------------------------------------------------- /source/is-never.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Returns a boolean for whether the given type is `never`. 3 | 4 | @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919 5 | @link https://stackoverflow.com/a/53984913/10292952 6 | @link https://www.zhenghao.io/posts/ts-never 7 | 8 | Useful in type utilities, such as checking if something does not occur. 9 | 10 | @example 11 | ``` 12 | import type {IsNever, And} from 'type-fest'; 13 | 14 | // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts 15 | type AreStringsEqual = 16 | And< 17 | IsNever> extends true ? true : false, 18 | IsNever> extends true ? true : false 19 | >; 20 | 21 | type EndIfEqual = 22 | AreStringsEqual extends true 23 | ? never 24 | : void; 25 | 26 | function endIfEqual(input: I, output: O): EndIfEqual { 27 | if (input === output) { 28 | process.exit(0); 29 | } 30 | } 31 | 32 | endIfEqual('abc', 'abc'); 33 | //=> never 34 | 35 | endIfEqual('abc', '123'); 36 | //=> void 37 | ``` 38 | 39 | @category Type Guard 40 | @category Utilities 41 | */ 42 | export type IsNever = [T] extends [never] ? true : false; 43 | -------------------------------------------------------------------------------- /source/conditional-except.d.ts: -------------------------------------------------------------------------------- 1 | import type {Except} from './except'; 2 | import type {ConditionalKeys} from './conditional-keys'; 3 | 4 | /** 5 | Exclude keys from a shape that matches the given `Condition`. 6 | 7 | This is useful when you want to create a new type with a specific set of keys from a shape. For example, you might want to exclude all the primitive properties from a class and form a new shape containing everything but the primitive properties. 8 | 9 | @example 10 | ``` 11 | import type {Primitive, ConditionalExcept} from 'type-fest'; 12 | 13 | class Awesome { 14 | name: string; 15 | successes: number; 16 | failures: bigint; 17 | 18 | run() {} 19 | } 20 | 21 | type ExceptPrimitivesFromAwesome = ConditionalExcept; 22 | //=> {run: () => void} 23 | ``` 24 | 25 | @example 26 | ``` 27 | import type {ConditionalExcept} from 'type-fest'; 28 | 29 | interface Example { 30 | a: string; 31 | b: string | number; 32 | c: () => void; 33 | d: {}; 34 | } 35 | 36 | type NonStringKeysOnly = ConditionalExcept; 37 | //=> {b: string | number; c: () => void; d: {}} 38 | ``` 39 | 40 | @category Object 41 | */ 42 | export type ConditionalExcept = Except< 43 | Base, 44 | ConditionalKeys 45 | >; 46 | -------------------------------------------------------------------------------- /source/set-non-nullable.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Create a type that makes the given keys non-nullable, where the remaining keys are kept as is. 3 | 4 | If no keys are given, all keys will be made non-nullable. 5 | 6 | Use-case: You want to define a single model where the only thing that changes is whether or not some or all of the keys are non-nullable. 7 | 8 | @example 9 | ``` 10 | import type {SetNonNullable} from 'type-fest'; 11 | 12 | type Foo = { 13 | a: number | null; 14 | b: string | undefined; 15 | c?: boolean | null; 16 | } 17 | 18 | type SomeNonNullable = SetNonNullable; 19 | // type SomeNonNullable = { 20 | // a: number | null; 21 | // b: string; // Can no longer be undefined. 22 | // c?: boolean; // Can no longer be null, but is still optional. 23 | // } 24 | 25 | type AllNonNullable = SetNonNullable; 26 | // type AllNonNullable = { 27 | // a: number; // Can no longer be null. 28 | // b: string; // Can no longer be undefined. 29 | // c?: boolean; // Can no longer be null, but is still optional. 30 | // } 31 | ``` 32 | 33 | @category Object 34 | */ 35 | export type SetNonNullable = { 36 | [Key in keyof BaseType]: Key extends Keys 37 | ? NonNullable 38 | : BaseType[Key]; 39 | }; 40 | -------------------------------------------------------------------------------- /source/is-integer.d.ts: -------------------------------------------------------------------------------- 1 | import type {Not} from './internal'; 2 | import type {IsFloat} from './is-float'; 3 | import type {PositiveInfinity, NegativeInfinity} from './numeric'; 4 | 5 | /** 6 | Returns a boolean for whether the given number is a integer, like `-5`, `1.0` or `100`. 7 | 8 | Like [`Number#IsInteger()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/IsInteger) but for types. 9 | 10 | Use-case: 11 | - If you want to make a conditional branch based on the result of whether a number is a intrger or not. 12 | 13 | @example 14 | ``` 15 | type Integer = IsInteger<1>; 16 | //=> true 17 | 18 | type IntegerWithDecimal = IsInteger<1.0>; 19 | //=> true 20 | 21 | type NegativeInteger = IsInteger<-1>; 22 | //=> true 23 | 24 | type Float = IsInteger<1.5>; 25 | //=> false 26 | 27 | // Supports non-decimal numbers 28 | 29 | type OctalInteger: IsInteger<0o10>; 30 | //=> true 31 | 32 | type BinaryInteger: IsInteger<0b10>; 33 | //=> true 34 | 35 | type HexadecimalInteger: IsInteger<0x10>; 36 | //=> true 37 | ``` 38 | */ 39 | export type IsInteger = 40 | T extends bigint 41 | ? true 42 | : T extends number 43 | ? number extends T 44 | ? false 45 | : T extends PositiveInfinity | NegativeInfinity 46 | ? false 47 | : Not> 48 | : false; 49 | -------------------------------------------------------------------------------- /test-d/unknown-array.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectNotAssignable, expectType} from 'tsd'; 2 | import type {UnknownArray} from '../index'; 3 | 4 | declare const foo: readonly []; 5 | declare const bar: { 6 | readonly array: unknown[]; 7 | }; 8 | 9 | expectAssignable(foo); 10 | expectAssignable(bar.array); 11 | expectAssignable([]); 12 | expectAssignable(['foo']); 13 | 14 | expectNotAssignable(null); 15 | expectNotAssignable(undefined); 16 | expectNotAssignable({}); 17 | expectNotAssignable({0: 1}); 18 | expectNotAssignable(1); 19 | expectNotAssignable(Date); 20 | 21 | type IsArray = T extends UnknownArray ? true : false; 22 | 23 | declare const string: IsArray; 24 | expectType(string); 25 | declare const array: IsArray<[]>; 26 | expectType(array); 27 | declare const tuple: IsArray<['foo']>; 28 | expectType(tuple); 29 | declare const readonlyArray: IsArray; 30 | expectType(readonlyArray); 31 | declare const leadingSpread: IsArray; 32 | expectType(leadingSpread); 33 | declare const trailingSpread: IsArray; 34 | expectType(trailingSpread); 35 | -------------------------------------------------------------------------------- /source/require-exactly-one.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Create a type that requires exactly one of the given keys and disallows more. The remaining keys are kept as is. 3 | 4 | Use-cases: 5 | - Creating interfaces for components that only need one of the keys to display properly. 6 | - Declaring generic keys in a single place for a single use-case that gets narrowed down via `RequireExactlyOne`. 7 | 8 | The caveat with `RequireExactlyOne` is that TypeScript doesn't always know at compile time every key that will exist at runtime. Therefore `RequireExactlyOne` can't do anything to prevent extra keys it doesn't know about. 9 | 10 | @example 11 | ``` 12 | import type {RequireExactlyOne} from 'type-fest'; 13 | 14 | type Responder = { 15 | text: () => string; 16 | json: () => string; 17 | secure: boolean; 18 | }; 19 | 20 | const responder: RequireExactlyOne = { 21 | // Adding a `text` key here would cause a compile error. 22 | 23 | json: () => '{"message": "ok"}', 24 | secure: true 25 | }; 26 | ``` 27 | 28 | @category Object 29 | */ 30 | export type RequireExactlyOne = 31 | {[Key in KeysType]: ( 32 | Required> & 33 | Partial, never>> 34 | )}[KeysType] & Omit; 35 | -------------------------------------------------------------------------------- /source/enforce-optional.d.ts: -------------------------------------------------------------------------------- 1 | import type {Simplify} from './simplify'; 2 | 3 | // Returns `never` if the key is optional otherwise return the key type. 4 | type RequiredFilter = undefined extends Type[Key] 5 | ? Type[Key] extends undefined 6 | ? Key 7 | : never 8 | : Key; 9 | 10 | // Returns `never` if the key is required otherwise return the key type. 11 | type OptionalFilter = undefined extends Type[Key] 12 | ? Type[Key] extends undefined 13 | ? never 14 | : Key 15 | : never; 16 | 17 | /** 18 | Enforce optional keys (by adding the `?` operator) for keys that have a union with `undefined`. 19 | 20 | @example 21 | ``` 22 | import type {EnforceOptional} from 'type-fest'; 23 | 24 | type Foo = { 25 | a: string; 26 | b?: string; 27 | c: undefined; 28 | d: number | undefined; 29 | }; 30 | 31 | type FooBar = EnforceOptional; 32 | // => { 33 | // a: string; 34 | // b?: string; 35 | // c: undefined; 36 | // d?: number; 37 | // } 38 | ``` 39 | 40 | @internal 41 | @category Object 42 | */ 43 | export type EnforceOptional = Simplify<{ 44 | [Key in keyof ObjectType as RequiredFilter]: ObjectType[Key] 45 | } & { 46 | [Key in keyof ObjectType as OptionalFilter]?: Exclude 47 | }>; 48 | -------------------------------------------------------------------------------- /test-d/iterable-element.ts: -------------------------------------------------------------------------------- 1 | import {expectAssignable, expectType} from 'tsd'; 2 | import type {IterableElement} from '../index'; 3 | 4 | declare const iterableElement: IterableElement>; 5 | expectType<1 | 'two'>(iterableElement); 6 | 7 | declare const iterableElementAsync: IterableElement>; 8 | expectType(iterableElementAsync); 9 | 10 | function * secretGenerator() { 11 | yield 1; 12 | yield 'two'; 13 | } 14 | 15 | async function * secretGeneratorAsync() { 16 | yield true; 17 | yield new Date(); 18 | } 19 | 20 | const fruits = new Set(['🍎', '🍌', '🍉'] as const); 21 | 22 | type Fruit = IterableElement; 23 | 24 | expectAssignable('🍎'); 25 | expectAssignable('🍌'); 26 | expectAssignable('🍉'); 27 | 28 | type VegetableSet = Set<'🥦' | '🥕' | '🌶'>; 29 | type Vegetable = IterableElement; 30 | 31 | expectAssignable('🥦'); 32 | expectAssignable('🥕'); 33 | expectAssignable('🌶'); 34 | 35 | type UserRolesSet = ReadonlySet<'regular' | 'contributor' | 'maintainer'>; 36 | type UserRole = IterableElement; 37 | 38 | expectAssignable('regular'); 39 | expectAssignable('contributor'); 40 | expectAssignable('maintainer'); 41 | -------------------------------------------------------------------------------- /source/literal-to-primitive-deep.d.ts: -------------------------------------------------------------------------------- 1 | import type {LiteralToPrimitive} from './literal-to-primitive'; 2 | import type {OmitIndexSignature} from './omit-index-signature'; 3 | 4 | /** 5 | Like `LiteralToPrimitive` except it converts literal types inside an object or array deeply. 6 | 7 | For example, given a constant object, it returns a new object type with the same keys but with all the values converted to primitives. 8 | 9 | @see LiteralToPrimitive 10 | 11 | Use-case: Deal with data that is imported from a JSON file. 12 | 13 | @example 14 | ``` 15 | import type {LiteralToPrimitiveDeep, TsConfigJson} from 'type-fest'; 16 | import tsconfig from 'path/to/tsconfig.json'; 17 | 18 | function doSomethingWithTSConfig(config: LiteralToPrimitiveDeep) { ... } 19 | 20 | // No casting is needed to pass the type check 21 | doSomethingWithTSConfig(tsconfig); 22 | 23 | // If LiteralToPrimitiveDeep is not used, you need to cast the imported data like this: 24 | doSomethingWithTSConfig(tsconfig as TsConfigJson); 25 | ``` 26 | 27 | @category Type 28 | @category Object 29 | */ 30 | export type LiteralToPrimitiveDeep = T extends object 31 | ? T extends Array 32 | ? Array> 33 | : { 34 | [K in keyof OmitIndexSignature]: LiteralToPrimitiveDeep; 35 | } 36 | : LiteralToPrimitive; 37 | -------------------------------------------------------------------------------- /source/merge.d.ts: -------------------------------------------------------------------------------- 1 | import type {OmitIndexSignature} from './omit-index-signature'; 2 | import type {PickIndexSignature} from './pick-index-signature'; 3 | import type {Simplify} from './simplify'; 4 | 5 | // Merges two objects without worrying about index signatures. 6 | type SimpleMerge = { 7 | [Key in keyof Destination as Key extends keyof Source ? never : Key]: Destination[Key]; 8 | } & Source; 9 | 10 | /** 11 | Merge two types into a new type. Keys of the second type overrides keys of the first type. 12 | 13 | @example 14 | ``` 15 | import type {Merge} from 'type-fest'; 16 | 17 | interface Foo { 18 | [x: string]: unknown; 19 | [x: number]: unknown; 20 | foo: string; 21 | bar: symbol; 22 | } 23 | 24 | type Bar = { 25 | [x: number]: number; 26 | [x: symbol]: unknown; 27 | bar: Date; 28 | baz: boolean; 29 | }; 30 | 31 | export type FooBar = Merge; 32 | // => { 33 | // [x: string]: unknown; 34 | // [x: number]: number; 35 | // [x: symbol]: unknown; 36 | // foo: string; 37 | // bar: Date; 38 | // baz: boolean; 39 | // } 40 | ``` 41 | 42 | @category Object 43 | */ 44 | export type Merge = 45 | Simplify< 46 | SimpleMerge, PickIndexSignature> 47 | & SimpleMerge, OmitIndexSignature> 48 | >; 49 | -------------------------------------------------------------------------------- /source/set-optional.d.ts: -------------------------------------------------------------------------------- 1 | import type {Except} from './except'; 2 | import type {HomomorphicPick} from './internal'; 3 | import type {KeysOfUnion} from './keys-of-union'; 4 | import type {Simplify} from './simplify'; 5 | 6 | /** 7 | Create a type that makes the given keys optional. The remaining keys are kept as is. The sister of the `SetRequired` type. 8 | 9 | Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are optional. 10 | 11 | @example 12 | ``` 13 | import type {SetOptional} from 'type-fest'; 14 | 15 | type Foo = { 16 | a: number; 17 | b?: string; 18 | c: boolean; 19 | } 20 | 21 | type SomeOptional = SetOptional; 22 | // type SomeOptional = { 23 | // a: number; 24 | // b?: string; // Was already optional and still is. 25 | // c?: boolean; // Is now optional. 26 | // } 27 | ``` 28 | 29 | @category Object 30 | */ 31 | export type SetOptional = 32 | BaseType extends unknown // To distribute `BaseType` when it's a union type. 33 | ? Simplify< 34 | // Pick just the keys that are readonly from the base type. 35 | Except & 36 | // Pick the keys that should be mutable from the base type and make them mutable. 37 | Partial>> 38 | > 39 | : never; 40 | -------------------------------------------------------------------------------- /source/asyncify.d.ts: -------------------------------------------------------------------------------- 1 | import type {SetReturnType} from './set-return-type'; 2 | 3 | /** 4 | Create an async version of the given function type, by boxing the return type in `Promise` while keeping the same parameter types. 5 | 6 | Use-case: You have two functions, one synchronous and one asynchronous that do the same thing. Instead of having to duplicate the type definition, you can use `Asyncify` to reuse the synchronous type. 7 | 8 | @example 9 | ``` 10 | import type {Asyncify} from 'type-fest'; 11 | 12 | // Synchronous function. 13 | function getFooSync(someArg: SomeType): Foo { 14 | // … 15 | } 16 | 17 | type AsyncifiedFooGetter = Asyncify; 18 | //=> type AsyncifiedFooGetter = (someArg: SomeType) => Promise; 19 | 20 | // Same as `getFooSync` but asynchronous. 21 | const getFooAsync: AsyncifiedFooGetter = (someArg) => { 22 | // TypeScript now knows that `someArg` is `SomeType` automatically. 23 | // It also knows that this function must return `Promise`. 24 | // If you have `@typescript-eslint/promise-function-async` linter rule enabled, it will even report that "Functions that return promises must be async.". 25 | 26 | // … 27 | } 28 | ``` 29 | 30 | @category Async 31 | */ 32 | export type Asyncify any> = SetReturnType>>>; 33 | -------------------------------------------------------------------------------- /test-d/is-equal.ts: -------------------------------------------------------------------------------- 1 | import {expectType} from 'tsd'; 2 | import type {IsEqual} from '../index'; 3 | 4 | const notEqualNumberAndString: IsEqual = false; 5 | expectType(notEqualNumberAndString); 6 | 7 | const equalNumbers: IsEqual<1, 1> = true; 8 | expectType(equalNumbers); 9 | 10 | const notEqualAnyAndNumber: IsEqual = false; 11 | expectType(notEqualAnyAndNumber); 12 | 13 | const notEqualUnionAndNumber: IsEqual<1 | 2, 1> = false; 14 | expectType(notEqualUnionAndNumber); 15 | 16 | const notEqualAnyAndNever: IsEqual = false; 17 | expectType(notEqualAnyAndNever); 18 | 19 | const notEqualArrayOfAnyAndArrayOfNever: IsEqual<[any], [never]> = false; 20 | expectType(notEqualArrayOfAnyAndArrayOfNever); 21 | 22 | // Missing all generic parameters. 23 | // @ts-expect-error 24 | type A = IsEqual; 25 | 26 | // Missing `Y` generic parameter. 27 | // @ts-expect-error 28 | type B = IsEqual; 29 | 30 | // Test for issue https://github.com/sindresorhus/type-fest/issues/537 31 | type UnionType = IsEqual<{a: 1} & {a: 1}, {a: 1}>; // eslint-disable-line @typescript-eslint/no-duplicate-type-constituents 32 | expectType(true); 33 | 34 | type IntersectionType = IsEqual<{a: 1} | {a: 1}, {a: 1}>; // eslint-disable-line @typescript-eslint/no-duplicate-type-constituents 35 | expectType(true); 36 | -------------------------------------------------------------------------------- /source/set-readonly.d.ts: -------------------------------------------------------------------------------- 1 | import type {Except} from './except'; 2 | import type {HomomorphicPick} from './internal'; 3 | import type {KeysOfUnion} from './keys-of-union'; 4 | import type {Simplify} from './simplify'; 5 | 6 | /** 7 | Create a type that makes the given keys readonly. The remaining keys are kept as is. 8 | 9 | Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are readonly. 10 | 11 | @example 12 | ``` 13 | import type {SetReadonly} from 'type-fest'; 14 | 15 | type Foo = { 16 | a: number; 17 | readonly b: string; 18 | c: boolean; 19 | } 20 | 21 | type SomeReadonly = SetReadonly; 22 | // type SomeReadonly = { 23 | // a: number; 24 | // readonly b: string; // Was already readonly and still is. 25 | // readonly c: boolean; // Is now readonly. 26 | // } 27 | ``` 28 | 29 | @category Object 30 | */ 31 | export type SetReadonly = 32 | // `extends unknown` is always going to be the case and is used to convert any 33 | // union into a [distributive conditional 34 | // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). 35 | BaseType extends unknown 36 | ? Simplify< 37 | Except & 38 | Readonly>> 39 | > 40 | : never; 41 | -------------------------------------------------------------------------------- /source/override-properties.d.ts: -------------------------------------------------------------------------------- 1 | import type {Merge} from './merge'; 2 | 3 | /** 4 | Override existing properties of the given type. Similar to `Merge`, but enforces that the original type has the properties you want to override. 5 | 6 | This is useful when you want to override existing properties with a different type and make sure that these properties really exist in the original. 7 | 8 | @example 9 | ``` 10 | type Foo = { 11 | a: string 12 | b: string 13 | } 14 | type Bar = OverrideProperties 15 | //=> {a: string, b: number} 16 | 17 | type Baz = OverrideProperties 18 | // Error, type '{ c: number; }' does not satisfy the constraint '{ c: never; }' 19 | 20 | type Fizz = OverrideProperties 21 | // Error, type '{ b: number; c: number; }' does not satisfy the constraint '{ b: number; c: never; }' 22 | ``` 23 | 24 | @category Object 25 | */ 26 | export type OverrideProperties< 27 | TOriginal, 28 | // This first bit where we use `Partial` is to enable autocomplete 29 | // and the second bit with the mapped type is what enforces that we don't try 30 | // to override properties that doesn't exist in the original type. 31 | TOverride extends Partial> & { 32 | [Key in keyof TOverride]: Key extends keyof TOriginal 33 | ? TOverride[Key] 34 | : never; 35 | }, 36 | > = Merge; 37 | -------------------------------------------------------------------------------- /source/literal-union.d.ts: -------------------------------------------------------------------------------- 1 | import type {Primitive} from './primitive'; 2 | 3 | export type LiteralStringUnion = LiteralUnion; 4 | 5 | /** 6 | Allows creating a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. 7 | 8 | Currently, when a union type of a primitive type is combined with literal types, TypeScript loses all information about the combined literals. Thus, when such type is used in an IDE with autocompletion, no suggestions are made for the declared literals. 9 | 10 | This type is a workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729). It will be removed as soon as it's not needed anymore. 11 | 12 | @example 13 | ``` 14 | import type {LiteralUnion} from 'type-fest'; 15 | 16 | // Before 17 | 18 | type Pet = 'dog' | 'cat' | string; 19 | 20 | const pet: Pet = ''; 21 | // Start typing in your TypeScript-enabled IDE. 22 | // You **will not** get auto-completion for `dog` and `cat` literals. 23 | 24 | // After 25 | 26 | type Pet2 = LiteralUnion<'dog' | 'cat', string>; 27 | 28 | const pet: Pet2 = ''; 29 | // You **will** get auto-completion for `dog` and `cat` literals. 30 | ``` 31 | 32 | @category Type 33 | */ 34 | export type LiteralUnion< 35 | LiteralType, 36 | BaseType extends Primitive, 37 | > = LiteralType | (BaseType & Record); 38 | -------------------------------------------------------------------------------- /source/conditional-simplify.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | 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. 3 | 4 | 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. 5 | 6 | @internal 7 | @experimental 8 | @see Simplify 9 | @category Object 10 | */ 11 | export type ConditionalSimplify = Type extends ExcludeType 12 | ? Type 13 | : Type extends IncludeType 14 | ? {[TypeKey in keyof Type]: Type[TypeKey]} 15 | : Type; 16 | 17 | /** 18 | Recursively simplifies a type while including and/or excluding certain types from being simplified. 19 | 20 | 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. 21 | 22 | See {@link ConditionalSimplify} for usages and examples. 23 | 24 | @internal 25 | @experimental 26 | @category Object 27 | */ 28 | export type ConditionalSimplifyDeep = Type extends ExcludeType 29 | ? Type 30 | : Type extends IncludeType 31 | ? {[TypeKey in keyof Type]: ConditionalSimplifyDeep} 32 | : Type; 33 | -------------------------------------------------------------------------------- /source/int-closed-range.d.ts: -------------------------------------------------------------------------------- 1 | import type {IntRange} from './int-range'; 2 | import type {Sum} from './sum'; 3 | 4 | /** 5 | Generate a union of numbers. 6 | 7 | The numbers are created from the given `Start` (inclusive) parameter to the given `End` (inclusive) parameter. 8 | 9 | You skip over numbers using the `Step` parameter (defaults to `1`). For example, `IntClosedRange<0, 10, 2>` will create a union of `0 | 2 | 4 | 6 | 8 | 10`. 10 | 11 | Note: `Start` or `End` must be non-negative and smaller than `999`. 12 | 13 | Use-cases: 14 | 1. This can be used to define a set of valid input/output values. for example: 15 | ``` 16 | type Age = IntClosedRange<0, 120>; //=> 0 | 1 | 2 | ... | 119 | 120 17 | type FontSize = IntClosedRange<10, 20>; //=> 10 | 11 | ... | 19 | 20 18 | type EvenNumber = IntClosedRange<0, 10, 2>; //=> 0 | 2 | 4 | 6 | 8 | 10 19 | ``` 20 | 2. This can be used to define random numbers in a range. For example, `type RandomNumber = IntClosedRange<0, 100>;` 21 | 22 | @example 23 | ``` 24 | import type {IntClosedRange} from 'type-fest'; 25 | 26 | // Create union type `0 | 1 | ... | 9` 27 | type ZeroToNine = IntClosedRange<0, 9>; 28 | 29 | // Create union type `100 | 200 | 300 | ... | 900` 30 | type Hundreds = IntClosedRange<100, 900, 100>; 31 | ``` 32 | 33 | @see IntRange 34 | */ 35 | export type IntClosedRange = IntRange, Skip>; 36 | -------------------------------------------------------------------------------- /source/require-all-or-none.d.ts: -------------------------------------------------------------------------------- 1 | import type {RequireNone} from './internal'; 2 | 3 | /** 4 | Requires all of the keys in the given object. 5 | */ 6 | type RequireAll = Required>; 7 | 8 | /** 9 | Create a type that requires all of the given keys or none of the given keys. The remaining keys are kept as is. 10 | 11 | Use-cases: 12 | - Creating interfaces for components with mutually-inclusive keys. 13 | 14 | The caveat with `RequireAllOrNone` is that TypeScript doesn't always know at compile time every key that will exist at runtime. Therefore `RequireAllOrNone` can't do anything to prevent extra keys it doesn't know about. 15 | 16 | @example 17 | ``` 18 | import type {RequireAllOrNone} from 'type-fest'; 19 | 20 | type Responder = { 21 | text?: () => string; 22 | json?: () => string; 23 | secure: boolean; 24 | }; 25 | 26 | const responder1: RequireAllOrNone = { 27 | secure: true 28 | }; 29 | 30 | const responder2: RequireAllOrNone = { 31 | text: () => '{"message": "hi"}', 32 | json: () => '{"message": "ok"}', 33 | secure: true 34 | }; 35 | ``` 36 | 37 | @category Object 38 | */ 39 | export type RequireAllOrNone = ( 40 | | RequireAll 41 | | RequireNone 42 | ) & Omit; // The rest of the keys. 43 | -------------------------------------------------------------------------------- /source/has-required-keys.d.ts: -------------------------------------------------------------------------------- 1 | import type {RequiredKeysOf} from './required-keys-of'; 2 | 3 | /** 4 | Creates a type that represents `true` or `false` depending on whether the given type has any required fields. 5 | 6 | This is useful when you want to create an API whose behavior depends on the presence or absence of required fields. 7 | 8 | @example 9 | ``` 10 | import type {HasRequiredKeys} from 'type-fest'; 11 | 12 | type GeneratorOptions