[TypeScript] Make typescript stick - 2
If<C, T, F>
Implement a type that evaluates to T
if the type C
is true
or F
if C
is false
.
// Implement this type
type If<C, T, F> = C extends true ? T: F
// Tests
type cases = [
Expect<Equal<If<true, "apple", "pear">, "apple">>,
Expect<Equal<If<false, "orange", 42>, 42>>
]
LengthOfTuple<T>
Implement a type that evaluates to a numeric type literal, equivalent to the length of a specified tuple type T
type LengthOfTuple<T extends readonly any[]> = T['length']
// Tests
const Fruits = ["cherry", "banana"] as const
type cases = [
Expect<Equal<LengthOfTuple<[1, 2, 3]>, 3>>,
Expect<NotEqual<LengthOfTuple<[1, 2, 3]>, 2>>,
Expect<Equal<LengthOfTuple<typeof Fruits>, 2>>,
Expect<Equal<LengthOfTuple<[]>, 0>>
]
EndsWith<A, B>
Implement a type that evaluates to true
if the type A
ends with the type B
, otherwise false.
type EndsWith<A extends string, B extends string> = A extends `${any}${B}` ? true: false;
// Tests
type cases = [
Expect<Equal<EndsWith<"ice cream", "cream">, true>>,
Expect<Equal<EndsWith<"ice cream", "chocolate">, false>>
]
Concat<A, B>
Implement a type that concatenates two tuple types A
, and B
type Concat<A extends any[], B extends any[]> = [
...A,
...B
]
// Tests
type cases = [
Expect<Equal<Concat<[], []>, []>>,
Expect<Equal<Concat<[], ["hello"]>, ["hello"]>>,
Expect<
Equal<Concat<[18, 19], [20, 21]>, [18, 19, 20, 21]>
>,
Expect<
Equal<
Concat<[42, "a", "b"], [Promise<boolean>]>,
[42, "a", "b", Promise<boolean>]
>
>
]
IsTuple<T>
Implement a type IsTuple
, which takes an input type T
and returns whether T
is tuple type.
https://www.tutorialsteacher.com/typescript/typescript-tuple
// @errors: 2344
type Expect<T extends true> = T
type Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false
type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true
// ---cut---
// Implement this type
/* _____________ Your Code Here _____________ */
type IsTuple<T> = [T] extends [never]
? false
: T extends readonly any[]
? any[] extends T
? false
: true
: false;
type x = never extends any[] ? true: false
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<IsTuple<[]>, true>>,
Expect<Equal<IsTuple<[number]>, true>>,
Expect<Equal<IsTuple<readonly [1]>, true>>,
Expect<Equal<IsTuple<{ length: 1 }>, false>>,
Expect<Equal<IsTuple<number[]>, false>>,
Expect<Equal<IsTuple<never>, false>>,
]
TupleToNestedObject<P, V>
Given a tuple type T
that only contains string type, and a type U
, build an object recursively.
// Need to make F to be string type, then you could do [K in F]
type TupleToNestedObject<P extends any[], V> = P extends [infer F extends string, ...(infer RT)] ? {
[K in F]: TupleToNestedObject<RT, V>
}: V
// Tests
type cases = [
Expect<
Equal<TupleToNestedObject<["a"], string>, { a: string }>
>,
Expect<
Equal<
TupleToNestedObject<["a", "b"], number>,
{ a: { b: number } }
>
>,
Expect<
Equal<
TupleToNestedObject<["a", "b", "c"], boolean>,
{ a: { b: { c: boolean } } }
>
>,
Expect<Equal<TupleToNestedObject<[], boolean>, boolean>>
]
IndexOf<T, U>
Implement the type version of Array.indexOf
, IndexOf<T, U>
takes an Array T
, any U
and returns the index of the first U
in Array T
.
// T will be reduce to []
// ACC will has all the items
type IndexOf<T extends any[], U, ACC extends any[] = []> = T[0] extends U
? ACC['length']
: T extends [infer FIRST, ...infer REST]
? IndexOf<REST, U, [...ACC, FIRST]>
: -1
let x: IndexOf<[1, 2, 3], 2>
// Tests
type cases = [
Expect<Equal<IndexOf<[1, 2, 3], 2>, 1>>,
Expect<Equal<IndexOf<[2, 6, 3, 8, 4, 1, 7, 3, 9], 3>, 2>>,
Expect<Equal<IndexOf<[0, 0, 0], 2>, -1>>
]
Wrap function return type into Promise
import { expectType } from "tsd";
// IMPLEMENT THIS TYPE
export type WrapForPenpal<T> = {
[K in keyof T]: T[K] extends { (...args: infer Arga): infer RT }
? (...args: Arga) => RT extends Promise<any> ? RT : Promise<RT>
: T[K];
};
/**
* Test Scenario - Do not change anything below this line
*/
const methods = {
add(a: number, b: number): number {
return a + b;
},
doAsyncAdd(a: number, b: number): Promise<number> {
return Promise.resolve(a + b);
},
subtract(a: number, b: number): number {
return a - b;
},
};
const asyncMethods: WrapForPenpal<typeof methods> = {} as any;
let addPromise = asyncMethods.add(1, 2);
let addPromise2 = asyncMethods.doAsyncAdd(1, 2);
expectType<Promise<number>>(addPromise);
expectType<Promise<number>>(addPromise2);
// @ts-expect-error
expectType<typeof addPromise>("this should fail");
let subtractPromise = asyncMethods.subtract(1, 2);
expectType<Promise<number>>(subtractPromise);
// @ts-expect-error
expectType<typeof subtractPromise>("this should fail");