Team Disco
- Dylan Roberts
- James Viall
Typing the useState
React hook
// error, only accepts strings :/ setMyString(10);
// we can use a Generic Type Parameter to get type safety function useState< T>(initialState: T): [getter: T, setter: (newValue: T) => void] { let state = initialState; const setter = (newValue: T) => { state = newValue; } return [state, setter]; }
// return type is inferred by parameter type const [myObj, setMyObj] = useState({ value: 'default'}); // ^?
setMyString(10); // error setMyObj('object?') // error setMyObj({ MY_VALUE: 'value' }) // object, but not of same type: error
setMyObj({ value: "value" }) // correct
// Scope Codebase Example
// useGridSortState
(src/utilts/hooks.tsx:L464
)
Given some object with keys, we can create a type out of the keys
// Topic: `keyof` operator // type Point = { x: number; y: number }; type P = keyof Point; // ^?let Peas: P[];
// Scope Codebase Example
// useRoutingRedirect
(src/utils/hooks.tsx:L1660
)
// Javascript has this natively for run-time expression primitive types. // Prints "string" console.log(typeof "Hello world"); console.log(typeof (() => null));
// Typscript adds the ability to use this in a pure type context const s = "hello"; let n: typeof s; // ^?
// A more useful example
// Comboing keyof
with typeof
const TOOLTIP_DELAY_MAP = {
long: 500,
none: 0,
short: 350
};
interface ITooltipProps { delay?: keyof typeof TOOLTIP_DELAY_MAP; // ^? }
const Tooltip = ({ delay = "long" }: ITooltipProps): void => { console.log(delay); }; Tooltip({}); Tooltip({ delay: 'short'});
// Codebase Example
// useRoutingRedirect
(src/utils/hooks.tsx:L1660
)
Look up a specific property on another type
type Person = { age: number; name: string; alive: boolean }; type Age = Person["age"]; // ^? type I1 = Person["age" | "name"]; // ^?type I2 = Person[keyof Person]; // ^?
type AliveOrName = "alive" | "name"; type I3 = Person[AliveOrName]; // ^?
// EXAMPLE IN CODEBASE
// Element<T extends Array>
in types/grids.ts
“If I were to index into an Array, what type would its elements be?”
// GraphQl query data types in src/utils/hooks:L707
getParentIdAndNameFromQuery()
Types which act like if
statements in the type system
type Example2 = RegExp extends Animal ? number : string; // ^?
// EXAMPLE IN CODEBASE
// IEntityKey<T extends IEntityType>
src/types/entities.ts:L25
Build on Index Signatures to clear types based on other types
// Often used with `keyof` operator type OptionsFlags< Type> = { [Property in keyof Type]: boolean; }; type FeatureFlags = { darkMode: () => void; newUserProfile: () => void; };type FeatureOptions = OptionsFlags< FeatureFlags>; // ^?
// EXAMPLE IN CODEBASE
// RecursivePartial<T>
in src/types/ctvo.ts:L246
Mapped types which change properties via template string literals
type World = "world";type Greeting = hello ${World}
;
// ^?
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
type AllLocaleIDs = ${EmailLocaleIDs | FooterLocaleIDs}_id
;
// ^?
type Lang = "en" | "ja" | "pt";
type LocaleMessageIDs = ${Lang}_${AllLocaleIDs}
;
// ^?
// EXAMPLE IN CODEBASE
// Entity String Types in src/types/entitites.ts
- TS Docs - Object Types & Intersection See: Intersection Types vs Interface extends
- TS Docs - More on Mapped Types See: Mapping Modifiers, and Key Remapping via ‘as’