Posted 11/28/2024
type OptionalString = string | null | undefined;
type NonNullString = NonNullable<OptionalString>; // string
type User = { id: number; name: string; email?: string };
type PartialUser = Partial<User>; // Makes all fields optional
type RequiredUser = Required<User>; // Makes all fields required
type ReadonlyUser = Readonly<User>; // Makes all fields readonly
type IsString<T> = T extends string ? true : false;
type Test1 = IsString<string>; // true
type Test2 = IsString<number>; // false
UseCase
type Response<T> = T extends "success" ? { data: string } : { error: string };
const handleResponse = <T extends "success" | "error">(status: T): Response<T> => {
if (status === "success") return { data: "Success!" } as Response<T>;
return { error: "Failed!" } as Response<T>;
};
type EventNames = "click" | "hover" | "focus";
type EventHandlers = `on${Capitalize<EventNames>}`; // "onClick" | "onHover" | "onFocus"
type RenameKeys<T> = {
[K in keyof T as `new_${string & K}`]: T[K];
};
type Original = { id: number; name: string };
type Renamed = RenameKeys<Original>; // { new_id: number; new_name: string }
type ApiEndpoints = {
[K in `GET_${string}` | `POST_${string}`]: () => void;
};
const api: ApiEndpoints = {
GET_user: () => console.log("Fetch user"),
POST_order: () => console.log("Create order"),
};
A union type ** | ** only requires the object to match one of the types, but it allows extra properties. |
// Type '"hello"'
let x = "hello" as const;
// Type 'readonly [10, 20]'
let y = [10, 20] as const;
// Type '{ readonly text: "hello" }'
let z = { text: "hello" } as const;
More details https://www.omarileon.me/blog/typescript-as-const
type Parse<T extends string> = T extends `${infer Line}\n${infer Rest}`
? Trim<Line> extends "" // Check if the trimmed line is empty
? Parse<Rest> // Skip empty or whitespace-only lines
: [ParseLine<Trim<Line>>, ...Parse<Rest>]
: Trim<T> extends "" // Handle the last line
? []
: [ParseLine<Trim<T>>];
// Trim whitespaces and \n, \t, \r
type Trim<T extends string> = T extends ` ${infer Rest}` | `\t${infer Rest}` | `${infer Rest} ` | `${infer Rest}\t` | `${infer Rest}\r`
? Trim<Rest>
: T;
type ParseLine<T extends string> =
T extends `let ${infer Id} = ${string}` | `var ${infer Id} = ${string}` | `const ${infer Id} = ${string}`
? { id: Id; type: "VariableDeclaration" }
: T extends `${infer Func}(${infer Arg});`
? { argument: Arg; type: "CallExpression" }
: T;
//Expected result
[
{
id: "teddyBear",
type: "VariableDeclaration"
},
{
argument: "teddyBear",
type: "CallExpression"
}
]