Skip to content

Instantly share code, notes, and snippets.

@dmitriy-novikov
Last active November 5, 2020 12:52
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmitriy-novikov/f27bfdd23fe0bf2188b221c255b9e963 to your computer and use it in GitHub Desktop.
Save dmitriy-novikov/f27bfdd23fe0bf2188b221c255b9e963 to your computer and use it in GitHub Desktop.
Action Type Inference
import * as actions from 'action-creators';
// Тип, который берет action-creators, выводит типы всех экшенов по отдельности и собирает их в union
type InferValueTypes<T> = T extends { [key: string]: infer U }
? U
: never;
type ActionTypes = ReturnType<InferValueTypes<typeof actions>>;
// Примеры кода из разных частей презентации
// Numeric Literal Type
type onlyNumberOne = 1
const a:onlyNumberOne = 1;
const b:onlyNumberOne = 2; // error
// String Literal Type
type onlyFoo = 'foo'
const a:onlyFoo = 'foo';
const b:onlyFoo = 'bar'; //error
// Generic
function returnTheSame<T>(arg: T): T {
return arg;
}
// Extends
function inferLiteralFromString<T extends string>(arg: T): T {
return arg;
}
const a = inferLiteralFromString<string>('some string'); // string
const b = inferLiteralFromString<'some string'>('some string'); // 'some string'
const c = inferLiteralFromString<number>(100500); //error
// Mapped type
type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]: boolean };
type mapOfBool = { [key: string]: boolean };
// Conditional type
type onlyString<T> = T extends string ? string : never
const a:onlyString<string> = 'some string'; // string
const b:onlyString<'some string'> = 'some string'; // string
const c:onlyString<number> = 42; // error
// Infer
type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type T1 = Foo<{ a: string, b: string }>; // string
type T2 = Foo<{ a: string, b: number }>; // string | number
// Более универсальный вариант сохранения литерального типа, чем string-literal-simple.ts
function inferLiteral<U, T extends U>(arg: T): T {
return arg;
}
function inferStringLiteral<T extends string>(arg: T): T {
return inferLiteral<string, T>(arg);
}
// В Typescript 3.4 можно использовать const assertion прямо в экшенах, без функций для сохранения литерального типа
const actionCreator1 = () => ({
type: 'action_with_foo',
foo: 'some_value'
} as const);
const actionCreator2 = () => (<const>{
type: 'action_with_bar',
bar: 100500
});
// Простая версия функции, которая сохраняет string literal
function inferLiteralFromString<T extends string>(arg: T): T {
return arg;
}
// И пример ее использования
const actionCreator1 = () => ({
type: inferLiteralFromString( 'action_with_foo'),
foo: 'some_value'
});
const actionCreator2 = () => ({
type: inferLiteralFromString('action_with_bar'),
bar: 100500
});
type ActionTypes = ReturnType<typeof actionCreator1> | ReturnType<typeof actionCreator2>;
const reducer = (state, action: ActionTypes) => {
switch (action.type) {
case 'action_with_bar':
return {...state, bar: action.bar };
case 'action_with_foo':
return {...state, foo: action.foo };
default:
return state;
}
};
@ilyahuman
Copy link

Подскажи плз откуда в T extends { [key: string]: infer U } берется U type ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment