mirror of
https://github.com/sindresorhus/type-fest.git
synced 2025-12-08 19:25:05 +00:00
98 lines
2.6 KiB
TypeScript
98 lines
2.6 KiB
TypeScript
import type {IsAny} from '../is-any.d.ts';
|
|
import type {IsLiteral} from '../is-literal.d.ts';
|
|
import type {ToString} from './string.d.ts';
|
|
|
|
// 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
|
|
/*
|
|
To prevent a problem where an object with only a `name` property is incorrectly treated as assignable to a function, we first check if the property is a record.
|
|
This check is necessary, because without it, if we don't verify whether the property is a record, an object with a type of `{name: any}` would return `never` due to its potential assignability to a function.
|
|
See: https://github.com/sindresorhus/type-fest/issues/657
|
|
*/
|
|
: Type[Key] extends Record<string, unknown>
|
|
? Key
|
|
: [(...arguments_: any[]) => any] extends [Type[Key]]
|
|
? never
|
|
: Key;
|
|
|
|
/**
|
|
Returns the required keys.
|
|
*/
|
|
export 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.
|
|
*/
|
|
export 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
|
|
>;
|
|
|
|
/**
|
|
Disallows any of the given keys.
|
|
*/
|
|
export type RequireNone<KeysType extends PropertyKey> = Partial<Record<KeysType, never>>;
|
|
|
|
/**
|
|
Utility type to retrieve only literal keys from type.
|
|
*/
|
|
export type LiteralKeyOf<T> = keyof {[K in keyof T as IsLiteral<K> extends true ? K : never]-?: never};
|
|
|
|
/**
|
|
Get the exact version of the given `Key` in the given object `T`.
|
|
|
|
Use-case: You known that a number key (e.g. 10) is in an object, but you don't know how it is defined in the object, as a string or as a number (e.g. 10 or '10'). You can use this type to get the exact version of the key. See the example.
|
|
|
|
@example
|
|
```
|
|
type Object = {
|
|
0: number;
|
|
'1': string;
|
|
};
|
|
|
|
type Key1 = ExactKey<Object, '0'>;
|
|
//=> 0
|
|
type Key2 = ExactKey<Object, 0>;
|
|
//=> 0
|
|
|
|
type Key3 = ExactKey<Object, '1'>;
|
|
//=> '1'
|
|
type Key4 = ExactKey<Object, 1>;
|
|
//=> '1'
|
|
```
|
|
|
|
@category Object
|
|
*/
|
|
export type ExactKey<T extends object, Key extends PropertyKey> =
|
|
Key extends keyof T
|
|
? Key
|
|
: ToString<Key> extends keyof T
|
|
? ToString<Key>
|
|
: Key extends `${infer NumberKey extends number}`
|
|
? NumberKey extends keyof T
|
|
? NumberKey
|
|
: never
|
|
: never;
|