Тараненко Андрей, ИТ-Холдинг Т1
type HelloWorld = 'Hello' | 'World';
type Generic<T> = {
payload: T;
};
type StringPayload = Generic<string>;
type Generic<T extends string> = /* */;
type Generic<
Key extends keyof T,
T extends string
> = /* */;
type Generic<T extends Required<T>> = /* */;
type ToArray<T> = T extends any[]
? T
: T[];
ToArray<string>; // string[]
ToArray<string[]>; // string[]
type ArrayItem<T> = /* */;
type ArrayItem<T> = T extends any[]
? /* */
: never;
type ArrayItem<T> = T extends (infer U)[]
? U
: never;
type Checked = ArrayItem<number[]>; // number
type Generic<T> = GetNewType<T> extends infer U
? U
: never;
type Name = 'world';
type Greet = `Hello ${Name}!`;
type Greet = 'Hello world!';
type Name = 'world' | 'Everyone';
type Greet = `Hello ${Name}!`;
type Greet = 'Hello world!' | 'Hello Everyone!';
type Greet = `Hello ${string}!`;
'true' |
'fasle'
`${boolean}`
type IsGreeting<T> = T extends `Hello ${string}!`
? true
: false;
type IsGreeting = 'Oh, Hello world!))))' extends `${string}Hello ${string}!${string}`
? true
: false
type IsGreeting = falsetype IsGreeting = true
type Greet = 'Hello world!' extends `Hello ${infer U}!`
? U
: never;
type Greet = 'world'
const sendMetrics = (someImportantId: string) => {
/* */
};
sendMetrics(''); // 😢
const sendMetrics = (someImportantId: string) => {
if (!someImportantId) { /* ???????? */ }
/* */
};
sendMetrics(''); // 😢
type NotEmptyString = `${string}${string}`;
type NotEmptyString = string;
type NotEmptyString = `${any}${string}`;
type NotEmptyString = `${any}${string}`;
const sendMetrics = (someImportantId: NotEmptyString) => {
/* */
};
sendMetrics('1'); // Ok
sendMetrics('');
// ^^ Несовместимые типы
const process = (someImportantId: string) => {
if (!someImportantId) return;
sendMetrics(someImportantId);
// ^^^^^^^^^^^^^^^^ Несовместимые типы
};
const process = (someImportantId: string) => {
if (!someImportantId) return;
sendMetrics(someImportantId as NotEmptyString);
};
const isNotEmptyString = (
value: string
): value is NotEmptyString => !!value;
const process = (someImportantId: string) => {
if (!isNotEmptyString(someImportantId)) return;
sendMetrics(someImportantId);
};
type AtLeastTwoChars = `${any}${string}${string}`;
type AtLeastThreeChars = `${any}${string}${string}${string}`;
const kilometersToMeters = (value: number) => value * 1000;
const metersToKilometers = (value: number) => value / 1000;
type Kilometers = number;
type Meters = number;
const kilometersToMeters = (value: Kilometers) => value * 1000;
const metersToKilometers = (value: Meters) => value / 1000;
type Kilometers = number;
type Meters = number;
Kilometers === Meters;
type Kilometer = number & {
__brand: 'Kilometer';
};
const symbol = Symbol();
declare const symbol: unique symbol;
declare const kilometersBrand: unique symbol;
type Kilometers = number & {
[kilometersBrand]: never;
};
type Brand<
TType,
TBrand extends symbol
> = TType & { [key in TBrand]: never };
type BrandedNumber<
TBrand extends symbol
> = Brand<number, TBrand>;
type Kilometers = BrandedNumber<typeof kilometersBrand>;
type Meters = BrandedNumber<typeof metersBrand>;
const kilometersToMeters = (value: Kilometers) => value * 1000;
const metersToKilometers = (value: Meters) => value / 1000;
let distance!: Kilometers;
kilometersToMeters(distance);
metersToKilometers(distance);
// ^^^^^^^^ Не совместимые типы
metersToKilometers(1000);
metersToKilometers(1000 as Meters);
type Meters = BrandedNumber<typeof metersBrand>;
type Radius = BrandedNumber<typeof radiusBrand>;
const circleSquare = (radius: Radius & Meters) =>
Math.PI * radius ** 2;
type ResponseData = {
time_stamp: string;
short_name: string;
full_name: string;
};
type ResponseData = {
time_stamp: string;
short_name: string;
full_name: string;
};
type Data = {
timeStamp: string;
shortName: string;
fullName: string;
};
type Type = {/* ... */};
type MappedType = {
[Key in keyof Type]: Type[Key];
}
type Type = {/* ... */};
type MappedType = {
readonly [Key in keyof Type]?: Type[Key];
}
type Type = {/* ... */};
type MappedType = {
+readonly [Key in keyof Type]+?: Type[Key];
}
type Type = {/* ... */};
type MappedType = {
-readonly [Key in keyof Type]-?: Type[Key];
}
type Type = {/* ... */};
type MappedType = {
[Key in keyof Type as Transform<Key>]: Type[Key];
}
SnakeToCamelCase<'snake_case_string'>
'snake_case_string'
'snake' 'case_string'
'snake' 'Case_string'
'snake' + SnakeToCamelCase<'Case_string'>
type FromSnakeToCamelCase<
SnakeCaseString extends string,
ProcessedPart extends string = ''
> = SnakeCaseString extends `${infer Word}_${infer Rest}`
? FromSnakeToCamelCase<Capitalize<Rest>, `${ProcessedPart}${Word}`>
: `${ProcessedPart}${SnakeCaseString}`;
type FromSnakeToCamelCase<
SnakeCaseString extends string
> = SnakeCaseString extends `${infer Word}_${infer Rest}`
? `${Capitalize<Word>}${FromSnakeToCamelCase<Rest>}`
: SnakeCaseString;
type ResponseData = {
time_stamp: string;
short_name: string;
full_name: string;
};
type Data = ObjectToCamelCase<ResponseData>
type ShortData = { id: string };
type AdditionData = { value: string };
type Data = ShortData & AdditionData;
type Prettify<T> = T extends object
? { [K in keyof T]: Prettify<T[K]> }
: T;
type Data = Prettify<ShortData & AdditionData>;
type Data = {
id: string;
value: string;
};