00014 Easy First of Array
https://github.com/type-challenges/type-challenges/tree/main/questions/00014-easy-first
Implement a generic First<T>
that takes an Array T
and returns itβs first elementβs type.
For example:
type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];
type head1 = First<arr1>; // expected to be 'a'
type head2 = First<arr2>; // expected to be 3
Tests
import type { Equal, Expect } from "@type-challenges/utils";
type cases = [
Expect<Equal<First<[3, 2, 1]>, 3>>,
Expect<Equal<First<[() => 123, { a: string }]>, () => 123>>,
Expect<Equal<First<[]>, never>>,
Expect<Equal<First<[undefined]>, undefined>>
];
type errors = [
// @ts-expect-error
First<"notArray">,
// @ts-expect-error
First<{ 0: "arrayLike" }>
];
Solution 1
Our first thought was like this:
type First<T extends any[]> = T[0];
This will solve most of test cases, but failed when T
is an empty array. So we can add a conditional return:
type First<T extends any[]> = T extends [] ? never : T[0];
Solution 2
Instead of checking T extends []
, we can check its length type. From previous tests we know thereβs a length
property on array/tuple type, so we can do:
type First<T extends any[]> = T["length"] extends 0 ? never : T[0];
Solution 3
We can also check if T[0]
is in array:
type First<T extends any[]> = T[0] extends T[number] ? T[0] : never;
Solution 4
We can also use infer
to get the type of the first element of the array:
type First<T extends any[]> = T extends [infer FIRST, ...infer REST]
? FIRST
: never;
00018 Easy Tuple Length
https://github.com/type-challenges/type-challenges/tree/main/questions/00018-easy-tuple-length
Create a generic Length, pick the length of the tuple.
For example:
type tesla = ["tesla", "model 3", "model X", "model Y"];
type spaceX = [
"FALCON 9",
"FALCON HEAVY",
"DRAGON",
"STARSHIP",
"HUMAN SPACEFLIGHT"
];
type teslaLength = Length<tesla>; // expected 4
type spaceXLength = Length<spaceX>; // expected 5
Tests
import type { Equal, Expect } from "@type-challenges/utils";
const tesla = ["tesla", "model 3", "model X", "model Y"] as const;
const spaceX = [
"FALCON 9",
"FALCON HEAVY",
"DRAGON",
"STARSHIP",
"HUMAN SPACEFLIGHT",
] as const;
type cases = [
Expect<Equal<Length<typeof tesla>, 4>>,
Expect<Equal<Length<typeof spaceX>, 5>>,
// @ts-expect-error
Length<5>,
// @ts-expect-error
Length<"hello world">
];
Solution
This is an easy one. From the examples and tests we can see Length
accepts constant tuple. and we can use length
property of array/tuple type to get the length. So itβll be like this:
type Length<T extends readonly any[]> = T["length"];
Summary
π keyof T
Operator
To get all keys as a union type from a type or interface, we can use mapped types in
.
type Point = { x: number; y: number };
type P = keyof Point;
// P is the same type as βxβ | βyβ
More on this: https://www.typescriptlang.org/docs/handbook/2/keyof-types.html#handbook-content
π [KEY in KTYPES]
A mapped type is a generic type which uses a union of PropertyKeys (frequently created via a keyof) to iterate through keys to create a type.
More on this:
https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#handbook-content
π TODO[KEY]
Indexed access type. We can use an indexed access type to look up a specific property on another type:
type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"];
// type Age = number
Indexed access type can also get the length of an array as a type.
const arr = [1, 3, 4];
type TLength = arr["length"];
More on this: https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html#handbook-content
π extends
The keyword extends
stands for constraints when defining a generic type.
π Native ReadOnly
type will do as the following:
interface Todo {
title: string
description: string
}
const todo: Readonly<Todo> = {
title: "Hey",
description: "foobar"
}
// will make `todo` as a readonly object:
const todo: <Todo> = {
readonly title: "Hey",
readonly description: "foobar"
}
More on ReadOnly
: https://www.tutorialsteacher.com/typescript/typescript-readonly
π as const
operator
const tuple = ['tesla', 'model 3'] as const
// will be equivalent to
typeof tuple = readonly ['tesla', 'model 3']`
π To get all values from an array type:
We can do ARR[number]
to get all values as an union type of the array type ARR
and use E in ARR[number]
to iterate through.
π To get type of the first element in an array
T[0]
π Get length of an array
T['length']
//also known as indexed
π extends union type
If we check whether a
extends a|2|3
, it will check every type in union type to see if they match.
π infer
in array destruction
T extends [infer FIRST, ...infer REST] ? FIRST : never
if FIRST
can be successfully destructed, then return FIRST
const arr: any[] = []
const [a, ...b] = arr
a ==> undefined
b ==> []
To be continuedβ¦