00268 Easy If
https://github.com/type-challenges/type-challenges/tree/main/questions/00268-easy-if
Implement a util If which accepts condition C, a truthy return type T, and a falsy return type F. C is expected to be either true or false while T and F can be any type.
For example:
type A = If<true, "a", "b">; // expected to be 'a'
type B = If<false, "a", "b">; // expected to be 'b'
Tests
import type { Equal, Expect } from "@type-challenges/utils";
type cases = [
  Expect<Equal<If<true, "a", "b">, "a">>,
  Expect<Equal<If<false, "a", 2>, 2>>
];
// @ts-expect-error
type error = If<null, "a", "b">;
Solution
This is an easy one. From previous questions we know we can restrict C to extend boolean and use a tertiary expression to return T or F.
type If<C extends boolean, T, F> = C extends true ? T : F;
By now we should get all tests pass. If thereโs still any error in type error = If<null, 'a', 'b'>, it is because in TS non-strict mode, null can extend boolean. We can simple turn on strict mode.
    "strict": true, // Enable all strict type-checking options.
    "strictNullChecks": true, // When type checking, take into account 'null' and 'undefined'.
00898 Easy includes
https://github.com/type-challenges/type-challenges/tree/main/questions/00898-easy-includes
Implement the JavaScript Array.includes function in the type system. A type takes the two arguments. The output should be a boolean true or false.
For example:
type isPillarMen = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">; // expected to be `false`
Test cases
import type { Equal, Expect } from "@type-challenges/utils";
import { Includes } from "./template";
type cases = [
  Expect<
    Equal<Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Kars">, true>
  >,
  Expect<
    Equal<Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">, false>
  >,
  Expect<Equal<Includes<[1, 2, 3, 5, 6, 7], 7>, true>>,
  Expect<Equal<Includes<[1, 2, 3, 5, 6, 7], 4>, false>>,
  Expect<Equal<Includes<[1, 2, 3], 2>, true>>,
  Expect<Equal<Includes<[1, 2, 3], 1>, true>>,
  Expect<Equal<Includes<[{}], { a: "A" }>, false>>,
  Expect<Equal<Includes<[boolean, 2, 3, 5, 6, 7], false>, false>>,
  Expect<Equal<Includes<[true, 2, 3, 5, 6, 7], boolean>, false>>,
  Expect<Equal<Includes<[false, 2, 3, 5, 6, 7], false>, true>>,
  Expect<Equal<Includes<[{ a: "A" }], { readonly a: "A" }>, false>>,
  Expect<Equal<Includes<[{ readonly a: "A" }], { a: "A" }>, false>>,
  Expect<Equal<Includes<[1], 1 | 2>, false>>,
  Expect<Equal<Includes<[1 | 2], 1>, false>>,
  Expect<Equal<Includes<[null], undefined>, false>>,
  Expect<Equal<Includes<[undefined], null>, false>>
];
Solution
My first thought on this one would be this:
type Includes<T extends readonly any[], U> = U extends T[number] ? true : false;
Unfortunately, it fails on some tests. The reason is the expression U extends T[number] ? true : false will compare the type of every elements in T with U, and return true or false for each comparison, in the end, the type would be a union type of all true/false results.true | true would be true and true | false will be boolean
We can use another approach to use infer to get each element of the array and use the provided Equal function to recursively do comparisons.
type Includes<T extends readonly any[], U>
  = T extends [infer FIRST, ...infer REST]
    ? Equal<FIRST, U> ? true : Includes<REST, U>
    : false
Summary
We can recursively use this Include type by passing REST as a generic type.
03057 Easy Push & 03060 Easy Unshift
https://github.com/type-challenges/type-challenges/tree/main/questions/03057-easy-push
https://github.com/type-challenges/type-challenges/tree/main/questions/03060-easy-unshift
Implement the generic version of Array.push
For example:
type Result = Push<[1, 2], "3">; // [1, 2, '3']
Implement the type version of Array.unshift
For example:
type Result = Unshift<[1, 2], 0>; // [0, 1, 2,]
The Solution would be the same as concat, which is to use the spread operator to create a new array type.
// Push
type Push<T extends any[], U> = [...T, U];
// Unshift
type Push<T extends any[], U> = [...T, U];
Summary
The spread operator can also be used on type.
03312 Easy Parameter
Implement the built-in Parameters<T> generic without using it.
For example:
const foo = (arg1: string, arg2: number): void => {};
type FunctionParamsType = MyParameters<typeof foo>; // [arg1: string, arg2: number]
Testing
import type { Equal, Expect } from "@type-challenges/utils";
const foo = (arg1: string, arg2: number): void => {};
const bar = (arg1: boolean, arg2: { a: "A" }): void => {};
const baz = (): void => {};
type cases = [
  Expect<Equal<MyParameters<typeof foo>, [string, number]>>,
  Expect<Equal<MyParameters<typeof bar>, [boolean, { a: "A" }]>>,
  Expect<Equal<MyParameters<typeof baz>, []>>
];
Solution
We can use infer to get the type of function parameter.
type MyParameters<T extends (...args: any[]) => any> = T extends (...infer ARGS) => any ? ARGS : never
Till now, we have finish all EASY level questions.๐๐