Open4
TSの型をこねこねする
swapに型を付ける
const temp = object[key1];
object[key1] = object[key2];
object[key2] = temp;
だめなの
// asserts-isでは型を拡張できない
declare const swap: <T, K extends keyof T>(object: T, key1: K, key2: K) =>
asserts object is T & { [_ in K]: T[K] };
const obj = { hoge: "", fuga: 0 };
swap(obj, "hoge", "fuga");
// ここでも`obj.hoge`の型がstringのまま(string | numberであるべき)
よさげなの
Intersection
type Swapable<T, K extends keyof T> =
{
[_ in K]: Intersection<
K extends unknown ? { x: T[K] } : never
> extends { x: infer U } ? U : never;
};
declare const swap: <T, K extends keyof T>(object: T & Swapable<T, K>, key1: K, key2: K) => void;
Repeat
type Range09 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type Times<T, U extends Range09> = {
0: [];
1: [T];
2: [T, T];
3: [T, T, T];
4: [T, T, T, T];
5: [T, T, T, T, T];
6: [T, T, T, T, T, T];
7: [T, T, T, T, T, T, T];
8: [T, T, T, T, T, T, T, T];
9: [T, T, T, T, T, T, T, T, T];
};
type Repeat10<T extends readonly unknown[]> = [
...T, ...T, ...T, ...T, ...T,
...T, ...T, ...T, ...T, ...T,
];
type RepeatInternal<T, U extends string, V extends readonly T[]> = (
U extends `${infer X extends Range09}${infer Rest}`
? {
x: [...Repeat10<V>, ...Times<T, X>]
} extends { x: infer __ extends readonly T[] }
? Rest extends "" ? __ : RepeatInternal<T, Rest, __>
: never
: never
);
type Repeat<T, U extends number> = (
number extends U
? readonly T[]
: RepeatInternal<T, `${U}`, readonly []>
);
type RepeatR<T, U extends number> = (
number extends U ? readonly T[]
: U extends Range09 ? Times<T, U>
: `${U}` extends `${infer Rest extends number}${Range09}`
? [
...Repeat10<RepeatR<T, Rest>>,
...Times<T, `${U}` extends `${Rest}${infer X extends Range09}` ? X : never>,
]
: never
);
一番シンプルなの
type Repeat<T, U extends number, V extends unknown[] = []> =
V["length"] extends U ? V : Repeat<T, U, [...V, T]>;
non-nullableな型{}
で書くと意味が分かりづらいからNonNullable<unknown>
とか書くといいかも。