Skip to content

Instantly share code, notes, and snippets.

@captain-yossarian
Last active September 6, 2021 17:53
Show Gist options
  • Select an option

  • Save captain-yossarian/a8fbeb191c0710fcc4cac631855e563b to your computer and use it in GitHub Desktop.

Select an option

Save captain-yossarian/a8fbeb191c0710fcc4cac631855e563b to your computer and use it in GitHub Desktop.
TypeScript presentation

Typing React Props


Component overloading

import { FC } from "react";

type WithName = { name: string };

type WithPath = { path: string };

type WithStateProps = { tabs: WithName[] };

type WithRouterProps = { withRouter: true; baseUrl?: string; tabs: WithPath[]; };

const TabsWithRouter: FC = (props) => null; const TabsWithState: FC = (props) => null;

type TabsProps = WithStateProps | WithRouterProps;

const Tabs = (props: TabsProps) => { if (props.withRouter) { // error return <TabsWithRouter {...props} />; // error } return <TabsWithState {...props} />; // error };

const Test = () => (

{/* Should be error because of lack of withRouter */}
);
const enum Colors {
  Red = 1 << 1,
  Green = 1 << 2,
  Blue = 1 << 3,
  Yellow = Red | Green,
  Magenta = Blue | Red,
  Cyan = Green | Blue,
}

const hasRed = (color: Colors) => Boolean(color & Colors.Red)
hasRed(Colors.Magenta) // true
hasRed(Colors.Cyan) // false

/**
 * To make it more React friendly,
 * Let's assume we expect next Props:
 */
type Props = {
  active: boolean,
  top: boolean,
  external: boolean,
  optional: boolean,
}

// These props we are received
const propsA: Props = {
  active: true, // first bit
  top: false, // second bit
  external: false, // third bit
  optional: true // fourth bit
}

// This is how we can represent it
// BitMask is singleton, you don't need create it every time
const BitMask = {
  active: 1 << 1,
  top: 1 << 2,
  external: 1 << 3,
  optional: 1 << 4
} as const;

const propsA2 = BitMask.active | BitMask.optional // 00010 | 10000 =>  10010
// So, instead of passing the whole object every time, we can just use one number.
// propsA and propsA2 represent same data
// So every algebraic  SUM type can be represented as bit mask

v3.8 Five main features

  • Import type
  • Private Fields
  • Top Level Await
  • JSDoc Improvements
  • Watch Options

import type

Why?

Guaranteed Side-effect free syntax

Tools like Babel, which don’t type-check can be certain with 100% accuracy
whether to remove the import.

// Look at the JS, this isn't included in the output import {DangerDSLType} from "danger"

declare const myDSL: DangerDSLType

myDSL.bitbucket_cloud

// On the other hand, this one is... import {danger} from "danger" danger.git

// But why?

// TS keeps track of whether an import is a "JS" value // or a TypeScript type. import {DangerDSLJSONType, message} from "danger" message

// Babel cannot do this!

// So now Babel knows that it can always skip these // 'import type' statements import type {DangerUtilsDSL} from "danger"

// Because they can't be used with "JS" values: import type {markdown} from "danger"


import type

Guaranteed Side-effect-y imports

There are folks who want to rely on importing side-effects, but also import a type from that import


// This statement will get erased because of import elision.
import { SomeTypeFoo, SomeOtherTypeBar } from "./module-with-side-effects";

// This statement always sticks around.
import "./module-with-side-effects";

/**

  • Binary, Octal and Hexadecimal number representation */

/** *

const hasRed = (color: Colors) => Boolean(color & Colors.Red) hasRed(Colors.Magenta) // true hasRed(Colors.Cyan) // false /**

  • To make it more React friendly,
  • Let's assume we expect next Props: */ type Props = { active: boolean, top: boolean, external: boolean, optional: boolean, }

// These props we are received const propsA: Props = { active: true, // first bit top: false, // second bit external: false, // third bit optional: true // fourth bit }

// This is how we can represent it // BitMask is singleton, you don't need create it every time const BitMask = { active: 1 << 1, top: 1 << 2, external: 1 << 3, optional: 1 << 4 } as const;

const propsA2 = BitMask.active | BitMask.optional // 00010 | 10000 => 10010 // So, instead of passing the whole object every time, we can just use one number. // propsA and propsA2 represent same data // So every algebraic SUM type can be represented as bit mask

/**

  • And the main question is: How to opack JS regular objects into bits?
  • As a frontend developer, in 99% cases I have a deal with array ob objects, not array of numbers. */ const obj = { top: true, category: 242, id: 123_456 }; // boolean and numbers, not strings

/**

  • Constraints:
  • So, TOP can be either 1 or 0, the easy one (T)
  • no more than 999 categories (C)
  • no more than 1_000_000 ID's (I) */

/**

  • Let's start with IS'd encoding.
  • How many bits we should allocate for ID's?
  • 1_000_000..toString(2).length -> we should allocate 20 bits
  • How many bits for category?
  • 999..toString(2).length -> 10
  • And for top? - 1 bit, because it is a boolean
  • TOP: 1
  • CATEGORY: 10
  • ID's: 20
  • Result:
  • T(1)-CCCCCCCCCC(10)-IIIIIIIIIIIIIIIIIIII(20)
  • TCCCCCCCCCCIIIIIIIIIIIIIIIIIIII -> length 31

*/

const id_hex = 123_456..toString(16) // 1e240 // 11110001001000000 const category_hex = 242..toString(16) // f2 // 11110010 const top_hex = 1..toString(16) // 1 const result = 0x1f21e240 // 1 - f2 - 1e240, binary representation 1 11110010 000 11110001001000000 /**

  • I'd willing to bet that you are familiar whith such kind of numbers.
  • It is common pattern to encode errors in this way */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment