i can enforce the fix size of array by doing following:
export type ArrayOneOrMore<T> = {
0: T;
} & Array<T>;
export type ArrayTwoOrMore<T> = {
0: T;
1: T;
} & Array<T>;
another way to write this is like this, but i prefer Array because it’s more intiutive
export type ArrayOneOrMore<T> = {
0: T;
} & T[];
export type ArrayTwoOrMore<T> = {
0: T;
1: T;
} & T[];
+
or -
allows control over the mapped type modifier (?
or readonly
). -?
means must be all present, aka it removes optionality (?
type T = {
a: string
b?: string
}
// Note b is optional
const sameAsT: { [K in keyof T]: string } = {
a: 'asdf', // a is required
}
// Note a became optional
const canBeNotPresent: { [K in keyof T]?: string } = {
}
// Note b became required
const mustBePreset: { [K in keyof T]-?: string } = {
a: 'asdf',
b: 'asdf' // b became required
}
Required only one:
export type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Pick<
T,
Exclude<keyof T, Keys>
> &
{
[K in Keys]-?: Required<Pick<T, K>> & Partial<Record<Exclude<Keys, K>, undefined>>;
}[Keys];
// example:
interface User {
name?: string;
email?: string;
phone?: string;
}
// Must have exactly one of name, email, or phone
type SingleContactMethod = RequireOnlyOne<User, 'name' | 'email' | 'phone'>;
// Valid examples:
const valid1: SingleContactMethod = { name: 'John' };
const valid2: SingleContactMethod = { email: 'john@example.com' };
const valid3: SingleContactMethod = { phone: '123-456-7890' };
// Invalid examples (will cause type errors):
const invalid1: SingleContactMethod = {}; // No contact method
const invalid2: SingleContactMethod = { name: 'John', email: 'john@example.com' }; // Multiple contact methods
RequiredAtLeastOne:
export type RequireAtLeastOne<T> = {
[K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>;
}[keyof T];
Omit is for removing specific property from object
interface User {
id: number;
name: string;
email: string;
age: number;
}
// Create a type without 'email' and 'age' properties
type UserWithoutSensitiveInfo = Omit<User, 'email' | 'age'>;
// UserWithoutSensitiveInfo now only has 'id' and 'name'
const safeUser: UserWithoutSensitiveInfo = {
id: 1,
name: "John"
// email and age are not allowed
};
Exclude is for removing specific type from union type
// Exclude removes specific types from a union
type NumberOrString = number | string | boolean;
// Removes number and boolean from the union
type StringOnly = Exclude<NumberOrString, number | boolean>;
// StringOnly is now just 'string'
const value: StringOnly = "hello"; // OK
// const numValue: StringOnly = 42; // Would be a type error