type-fest
Advanced tools
Comparing version 3.2.0 to 3.3.0
{ | ||
"name": "type-fest", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"description": "A collection of essential TypeScript types", | ||
@@ -40,4 +40,4 @@ "license": "(MIT OR CC0-1.0)", | ||
"tsd": "^0.24.1", | ||
"typescript": "^4.8.4", | ||
"xo": "^0.52.4" | ||
"typescript": "^4.9.3", | ||
"xo": "^0.53.1" | ||
}, | ||
@@ -44,0 +44,0 @@ "xo": { |
@@ -71,16 +71,2 @@ <div align="center"> | ||
</a> | ||
<br> | ||
<br> | ||
<a href="https://sizzy.co/?utm_campaign=github_repo&utm_source=github&utm_medium=referral&utm_content=type-fest&utm_term=sindre"> | ||
<div> | ||
<img src="https://sindresorhus.com/assets/thanks/sizzy-logo.png" width="240" alt="Sizzy"> | ||
</div> | ||
<div> | ||
<sub> | ||
<b>Before Sizzy:</b> web development is stressing you out, responsive design is hard, you have an overwhelming amount of opened tabs & apps. | ||
<br> | ||
<b>After Sizzy:</b> all the tools you need in one place, responsive design is a breeze, no more context switching. | ||
</sub> | ||
</div> | ||
</a> | ||
</p> | ||
@@ -87,0 +73,0 @@ </div> |
import type {Primitive} from './primitive'; | ||
import type {Simplify} from './simplify'; | ||
@@ -111,1 +112,76 @@ /** | ||
export type IsNumeric<T extends string> = T extends `${number}` ? true : false; | ||
/** | ||
Returns a boolean for whether the the type is `any`. | ||
@link https://stackoverflow.com/a/49928360/1490091 | ||
*/ | ||
export type IsAny<T> = 0 extends 1 & T ? true : false; | ||
/** | ||
For an object T, if it has any properties that are a union with `undefined`, make those into optional properties instead. | ||
@example | ||
``` | ||
type User = { | ||
firstName: string; | ||
lastName: string | undefined; | ||
}; | ||
type OptionalizedUser = UndefinedToOptional<User>; | ||
//=> { | ||
// firstName: string; | ||
// lastName?: string; | ||
// } | ||
``` | ||
*/ | ||
export type UndefinedToOptional<T extends object> = Simplify< | ||
{ | ||
// Property is not a union with `undefined`, keep it as-is. | ||
[Key in keyof Pick<T, FilterDefinedKeys<T>>]: T[Key]; | ||
} & { | ||
// Property _is_ a union with defined value. Set as optional (via `?`) and remove `undefined` from the union. | ||
[Key in keyof Pick<T, FilterOptionalKeys<T>>]?: Exclude<T[Key], undefined>; | ||
} | ||
>; | ||
// Returns `never` if the key or property is not jsonable without testing whether the property is required or optional otherwise return the key. | ||
type BaseKeyFilter<Type, Key extends keyof Type> = Key extends symbol | ||
? never | ||
: Type[Key] extends symbol | ||
? never | ||
: [(...args: any[]) => any] extends [Type[Key]] | ||
? never | ||
: Key; | ||
/** | ||
Returns the required keys. | ||
*/ | ||
type FilterDefinedKeys<T extends object> = Exclude< | ||
{ | ||
[Key in keyof T]: IsAny<T[Key]> extends true | ||
? Key | ||
: undefined extends T[Key] | ||
? never | ||
: T[Key] extends undefined | ||
? never | ||
: BaseKeyFilter<T, Key>; | ||
}[keyof T], | ||
undefined | ||
>; | ||
/** | ||
Returns the optional keys. | ||
*/ | ||
type FilterOptionalKeys<T extends object> = Exclude< | ||
{ | ||
[Key in keyof T]: IsAny<T[Key]> extends true | ||
? never | ||
: undefined extends T[Key] | ||
? T[Key] extends undefined | ||
? never | ||
: BaseKeyFilter<T, Key> | ||
: never; | ||
}[keyof T], | ||
undefined | ||
>; |
@@ -26,6 +26,11 @@ /** | ||
Delimiter extends string, | ||
> = Strings extends [] ? '' : | ||
Strings extends [string | number] ? `${Strings[0]}` : | ||
// @ts-expect-error `Rest` is inferred as `unknown` here: https://github.com/microsoft/TypeScript/issues/45281 | ||
Strings extends [string | number, ...infer Rest] ? `${Strings[0]}${Delimiter}${Join<Rest, Delimiter>}` : | ||
string; | ||
> = Strings extends [] | ||
? '' | ||
: Strings extends [string | number] | ||
? `${Strings[0]}` | ||
: Strings extends [ | ||
string | number, | ||
...infer Rest extends Array<string | number>, | ||
] | ||
? `${Strings[0]}${Delimiter}${Join<Rest, Delimiter>}` | ||
: string; |
import type {JsonPrimitive, JsonValue} from './basic'; | ||
import type {EmptyObject} from './empty-object'; | ||
import type {Merge} from './merge'; | ||
import type {IsAny, UndefinedToOptional} from './internal'; | ||
import type {NegativeInfinity, PositiveInfinity} from './numeric'; | ||
@@ -10,22 +10,16 @@ import type {TypedArray} from './typed-array'; | ||
// Returns never if the key or property is not jsonable without testing whether the property is required or optional otherwise return the key. | ||
type BaseKeyFilter<Type, Key extends keyof Type> = Key extends symbol | ||
? never | ||
: Type[Key] extends symbol | ||
? never | ||
: [(...args: any[]) => any] extends [Type[Key]] | ||
? never | ||
: Key; | ||
type JsonifyTuple<T extends [unknown, ...unknown[]]> = { | ||
[Key in keyof T]: T[Key] extends NotJsonable ? null : Jsonify<T[Key]>; | ||
}; | ||
// Returns never if the key or property is not jsonable or optional otherwise return the key. | ||
type RequiredKeyFilter<Type, Key extends keyof Type> = undefined extends Type[Key] | ||
? never | ||
: BaseKeyFilter<Type, Key>; | ||
type FilterJsonableKeys<T extends object> = { | ||
[Key in keyof T]: T[Key] extends NotJsonable ? never : Key; | ||
}[keyof T]; | ||
// Returns never if the key or property is not jsonable or required otherwise return the key. | ||
type OptionalKeyFilter<Type, Key extends keyof Type> = undefined extends Type[Key] | ||
? Type[Key] extends undefined | ||
? never | ||
: BaseKeyFilter<Type, Key> | ||
: never; | ||
/** | ||
JSON serialize objects (not including arrays) and classes. | ||
*/ | ||
type JsonifyObject<T extends object> = { | ||
[Key in keyof Pick<T, FilterJsonableKeys<T>>]: Jsonify<T[Key]>; | ||
}; | ||
@@ -89,27 +83,34 @@ /** | ||
*/ | ||
export type Jsonify<T> = | ||
// Check if there are any non-JSONable types represented in the union. | ||
// Note: The use of tuples in this first condition side-steps distributive conditional types | ||
// (see https://github.com/microsoft/TypeScript/issues/29368#issuecomment-453529532) | ||
[Extract<T, NotJsonable | bigint>] extends [never] | ||
? T extends PositiveInfinity | NegativeInfinity ? null | ||
: T extends JsonPrimitive ? T // Primitive is acceptable | ||
: T extends object | ||
// Any object with toJSON is special case | ||
? T extends {toJSON(): infer J} ? (() => J) extends (() => JsonValue) // Is J assignable to JsonValue? | ||
? J // Then T is Jsonable and its Jsonable value is J | ||
: Jsonify<J> // Maybe if we look a level deeper we'll find a JsonValue | ||
// Instanced primitives are objects | ||
: T extends Number ? number | ||
: T extends String ? string | ||
: T extends Boolean ? boolean | ||
: T extends Map<any, any> | Set<any> ? EmptyObject | ||
: T extends TypedArray ? Record<string, number> | ||
: T extends any[] | ||
? {[I in keyof T]: T[I] extends NotJsonable ? null : Jsonify<T[I]>} | ||
: Merge< | ||
{[Key in keyof T as RequiredKeyFilter<T, Key>]: Jsonify<T[Key]>}, | ||
{[Key in keyof T as OptionalKeyFilter<T, Key>]?: Jsonify<Exclude<T[Key], undefined>>} | ||
> // Recursive call for its children | ||
: never // Otherwise any other non-object is removed | ||
: never; // Otherwise non-JSONable type union was found not empty | ||
export type Jsonify<T> = IsAny<T> extends true | ||
? any | ||
: T extends PositiveInfinity | NegativeInfinity | ||
? null | ||
: T extends JsonPrimitive | ||
? T | ||
: // Instanced primitives are objects | ||
T extends Number | ||
? number | ||
: T extends String | ||
? string | ||
: T extends Boolean | ||
? boolean | ||
: T extends Map<any, any> | Set<any> | ||
? EmptyObject | ||
: T extends TypedArray | ||
? Record<string, number> | ||
: T extends NotJsonable | ||
? never // Non-JSONable type union was found not empty | ||
: // Any object with toJSON is special case | ||
T extends {toJSON(): infer J} | ||
? (() => J) extends () => JsonValue // Is J assignable to JsonValue? | ||
? J // Then T is Jsonable and its Jsonable value is J | ||
: Jsonify<J> // Maybe if we look a level deeper we'll find a JsonValue | ||
: T extends [] | ||
? [] | ||
: T extends [unknown, ...unknown[]] | ||
? JsonifyTuple<T> | ||
: T extends ReadonlyArray<infer U> | ||
? Array<U extends NotJsonable ? null : Jsonify<U>> | ||
: T extends object | ||
? JsonifyObject<UndefinedToOptional<T>> // JsonifyObject recursive call for its children | ||
: never; // Otherwise any other non-object is removed |
@@ -1,4 +0,1 @@ | ||
import type {Except} from './except'; | ||
import type {Simplify} from './simplify'; | ||
/** | ||
@@ -38,8 +35,6 @@ Create a type that makes the given keys non-nullable, where the remaining keys are kept as is. | ||
*/ | ||
export type SetNonNullable<BaseType, Keys extends keyof BaseType = keyof BaseType> = | ||
Simplify< | ||
// Pick just the keys that are readonly from the base type. | ||
Except<BaseType, Keys> & | ||
// Pick the keys that should be non-nullable from the base type and make them non-nullable. | ||
{[Key in Keys]: NonNullable<BaseType[Key]>} | ||
>; | ||
export type SetNonNullable<BaseType, Keys extends keyof BaseType = keyof BaseType> = { | ||
[Key in keyof BaseType]: Key extends Keys | ||
? NonNullable<BaseType[Key]> | ||
: BaseType[Key]; | ||
}; |
@@ -1,2 +0,3 @@ | ||
type IsAny<T> = 0 extends (1 & T) ? true : false; // https://stackoverflow.com/a/49928360/3406963 | ||
import type {IsAny} from './internal'; | ||
type IsNever<T> = [T] extends [never] ? true : false; | ||
@@ -3,0 +4,0 @@ type IsUnknown<T> = IsNever<T> extends false ? T extends unknown ? unknown extends T ? IsAny<T> extends false ? true : false : false : false : false; |
238259
5528
903