abitype
Version:
Strict TypeScript types for Ethereum ABIs
229 lines (217 loc) • 6.43 kB
text/typescript
/**
* Prints custom error message
*
* @param messages - Error message
* @returns Custom error message
*
* @example
* type Result = Error<'Custom error message'>
* // ^? type Result = ['Error: Custom error message']
*/
export type Error<messages extends string | string[]> = messages extends string
? [
// Surrounding with array to prevent `messages` from being widened to `string`
`Error: ${messages}`,
]
: {
[key in keyof messages]: messages[key] extends infer message extends
string
? `Error: ${message}`
: never
}
/**
* Filters out all members of {@link items} that are {@link item}
*
* @param items - Items to filter
* @param item - Type to filter out
* @returns Filtered items
*
* @example
* type Result = Filter<['a', 'b', 'c'], 'b'>
* // ^? type Result = ['a', 'c']
*/
export type Filter<
items extends readonly unknown[],
item,
///
acc extends readonly unknown[] = [],
> = items extends readonly [
infer head,
...infer tail extends readonly unknown[],
]
? [head] extends [item]
? Filter<tail, item, acc>
: Filter<tail, item, [...acc, head]>
: readonly [...acc]
/**
* Checks if {@link type} can be narrowed further than {@link type2}
*
* @param type - Type to check
* @param type2 - Type to against
*
* @example
* type Result = IsNarrowable<'foo', string>
* // ^? true
*/
export type IsNarrowable<type, type2> = IsUnknown<type> extends true
? false
: IsNever<
(type extends type2 ? true : false) &
(type2 extends type ? false : true)
> extends true
? false
: true
/**
* Checks if {@link type} is `never`
*
* @param type - Type to check
*
* @example
* type Result = IsNever<never>
* // ^? type Result = true
*/
export type IsNever<type> = [type] extends [never] ? true : false
/**
* Checks if {@link type} is `unknown`
*
* @param type - Type to check
* @returns `true` if {@link type} is `unknown`, otherwise `false`
*
* @example
* type Result = IsUnknown<unknown>
* // ^? type Result = true
*/
export type IsUnknown<type> = unknown extends type ? true : false
/**
* Joins array into string
*
* @param array - Array to join
* @param separator - Separator
* @returns string
*
* @example
* type Result = Join<['a', 'b', 'c'], '-'>
* // ^? type Result = 'a-b-c'
*/
export type Join<
array extends readonly unknown[],
separator extends string | number,
> = array extends readonly [infer head, ...infer tail]
? tail['length'] extends 0
? `${head & string}`
: `${head & string}${separator}${Join<tail, separator>}`
: never
/**
* Merges two object types into new type
*
* @param object1 - Object to merge into
* @param object2 - Object to merge and override keys from {@link object1}
* @returns New object type with keys from {@link object1} and {@link object2}. If a key exists in both {@link object1} and {@link object2}, the key from {@link object2} will be used.
*
* @example
* type Result = Merge<{ foo: string }, { foo: number; bar: string }>
* // ^? type Result = { foo: number; bar: string }
*/
export type Merge<object1, object2> = Omit<object1, keyof object2> & object2
/**
* Makes objects destructurable.
*
* @param union - Union to distribute.
*
* @example
* type Result = OneOf<{ foo: boolean } | { bar: boolean }>
* // ^? type Result = { foo: boolean; bar?: undefined; } | { bar: boolean; foo?: undefined; }
*/
export type OneOf<
union extends object,
///
allKeys extends KeyofUnion<union> = KeyofUnion<union>,
> = union extends infer item
? Pretty<item & { [key in Exclude<allKeys, keyof item>]?: never }>
: never
type KeyofUnion<type> = type extends type ? keyof type : never
/**
* Combines members of an intersection into a readable type.
*
* @link https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg
* @example
* type Result = Pretty<{ a: string } | { b: string } | { c: number, d: bigint }>
* // ^? type Result = { a: string; b: string; c: number; d: bigint }
*/
export type Pretty<type> = { [key in keyof type]: type[key] } & unknown
/**
* Creates range between two positive numbers using [tail recursion](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html#tail-recursion-elimination-on-conditional-types).
*
* @param start - Number to start range
* @param stop - Number to end range
* @returns Array with inclusive range from {@link start} to {@link stop}
*
* @example
* type Result = Range<1, 3>
* // ^? type Result = [1, 2, 3]
*/
// From [Type Challenges](https://github.com/type-challenges/type-challenges/issues/11625)
export type Range<
start extends number,
stop extends number,
///
result extends number[] = [],
padding extends 0[] = [],
current extends number = [...padding, ...result]['length'] & number,
> = current extends stop
? current extends start
? [current]
: result extends []
? []
: [...result, current]
: current extends start
? Range<start, stop, [current], padding>
: result extends []
? Range<start, stop, [], [...padding, 0]>
: Range<start, stop, [...result, current], padding>
/**
* Trims empty space from type {@link t}.
*
* @param t - Type to trim
* @param chars - Characters to trim
* @returns Trimmed type
*
* @example
* type Result = Trim<' foo '>
* // ^? type Result = "foo"
*/
export type Trim<type, chars extends string = ' '> = TrimLeft<
TrimRight<type, chars>,
chars
>
type TrimLeft<t, chars extends string = ' '> = t extends `${chars}${infer tail}`
? TrimLeft<tail>
: t
type TrimRight<
t,
chars extends string = ' ',
> = t extends `${infer head}${chars}` ? TrimRight<head> : t
/**
* Create tuple of {@link type} type with {@link size} size
*
* @param Type - Type of tuple
* @param Size - Size of tuple
* @returns Tuple of {@link type} type with {@link size} size
*
* @example
* type Result = Tuple<string, 2>
* // ^? type Result = [string, string]
*/
// https://github.com/Microsoft/TypeScript/issues/26223#issuecomment-674500430
export type Tuple<type, size extends number> = size extends size
? number extends size
? type[]
: _TupleOf<type, size, []>
: never
type _TupleOf<
length,
size extends number,
acc extends readonly unknown[],
> = acc['length'] extends size
? acc
: _TupleOf<length, size, readonly [length, ...acc]>