Skip to content

Instantly share code, notes, and snippets.

type ObjectFromTuple<T extends string[]> =
FlattenObject< // 5. Делаем объект плоским
ToIntersect< // 4. Union to Intersection
{ // 2. { [key]: { [value]: value } }
[K in keyof T]: T[K] extends string
? Record<T[K], T[K]> // 1. { [value]: value }
: never
}[number] // 3. { [key]: { [value]: value } } -> { [value]: value } & { [value]: value }
>
>
// 1. Это вариант предпочтительней
function convertTupleToObject<T extends any[]>(...tuple: T) {
// ...
}
// vs
// 2. чем этот
function convertArrayToObject<T extends any[]>(array: T) {
// ...
@RubaXa
RubaXa / tuple-vs-const.ts
Last active December 20, 2019 09:34
Tuple vs. <const>
let tuple = createTuple('foo', true, { bar: 2019 });
// 1. readonly [string, boolean, { bar: number }]
let constArray = <const>['foo', true, { bar: 2019 }];
// 2. readonly [string, boolean, { bar: number }]
let justArray = ['foo', true, { bar: 2019 }];
// 3. (string | boolean | { bar: number })
function createTuple<T extends any[]>(...args: T): Readonly<T> {
@RubaXa
RubaXa / login.tsx
Last active September 5, 2019 07:50
Login
// 1. Переопределение через Провайдер зависимостей
const rootDeps = createDepsRegistry([ Input, Button ]);
const loginDeps = createDepsRegistry([ SupperButton ]);
<DepsProvider value={rootDeps}>
<div data-id="app">
<Informer/> {/* все кнопки в «Информере» в будут Button */}
<DepsProvider value={loginDeps}>
<div data-id="login">
@RubaXa
RubaXa / typings.ts
Created August 27, 2019 16:56
TrueSlots. SlotProp.
// Функциональный слот
type SlotWithValue< S extends SlotPropType, V, R > = (parent: S, val: V) => R
// Обычный слот
type SlotWithoutValue< S extends SlotPropType > = (parent: S) => S
// 🎰 А теперь в зависимости от того, какая у нас S-спека
// возвращаем обыччный слот, либо функциональный
type SlotProp< S extends SlotPropType > = null | (
S extends (value: infer V) => infer R // если S — функция
@RubaXa
RubaXa / usage.tsx
Last active August 27, 2019 11:50
TrueSlots. Usage.
// Нам больше не нужен `header`
<LoginForm
header={null}
/>
// Добавляем «крестик» и кнопку «Отмена»
<LoginForm
header={(parent) => <>
{parent()}
<Icon name="cross" onClick={...}/>
@RubaXa
RubaXa / describe.true.tsx
Last active August 27, 2019 10:50
TrueSlots. Finally.
const $LoginForm = createComponentDescriptor('@myapp/LoginForm', {} as LoginFormProps, {
Input: $Input,
Button: $Button,
});
type LoginFormProps = {
header?: Slot< SlotContent >; // 1️⃣Теперь это не boolean, а тоже слот,
// чтобы можно было его убрать
title?: Slot< SlotContent >; // 2️⃣ Заголовок
@RubaXa
RubaXa / describe.title.tsx
Last active August 27, 2019 06:44
TrueSlots
import { Slot, SlotComponent, createComponentDescriptor } from '@truekit/core/component';
type LoginFormProps = {
title?: Slot< SlotComponent >; // ⬅ опа 1️⃣
email?: string;
password?: string;
}
const $LoginForm = createComponentDescriptor('@myapp/LoginForm', {} as LoginFormProps);
@RubaXa
RubaXa / describe.titleElement.tsx
Last active August 27, 2019 10:32
Poor slots. Describe.
type LoginFormProps = {
header?: boolean;
title?: React.ReactNode;
titleEl?: React.ReactNode; // ⬅️ заметьте, я не глупый и делаю универсально
email?: string;
password?: string;
}
function LoginForm(props: LoginFormProps) {
const titleEl = props.titleEl || <h2/>;
@RubaXa
RubaXa / describe.header.tsx
Created August 26, 2019 15:31
Poor slots. Describe.
type LoginFormProps = {
header?: boolean; // ⬅ опа 1️⃣
title?: React.ReactNode;
email?: string;
password?: string;
}
function LoginForm(props: LoginFormProps) {
return (
<Form>