Last active
July 28, 2020 21:19
-
-
Save 3ZsForInsomnia/60b22f19507bb7cfcb183acbdf1394e1 to your computer and use it in GitHub Desktop.
Typescript expressive types workshop examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* `kind` is what is called a "discriminator", as it allows us to determine (at runtime) | |
* what type the returned data is, _without_ relying on introspection of the values in the data. | |
* | |
* This let's us do "if (claim.kind === 'prescription') ...", which is much less fragile or "hacky" than | |
* "if (Object.keys(claim).includes('surgeryType') ..." | |
*/ | |
type surgicalProcedure = { kind: 'surgicalProcedure'; surgeryType: string }; | |
type prescription = { kind: 'prescription'; refillsAllowed: number; medicationName: string }; | |
type claimsType = surgicalProcedure | prescription; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Basic Member type | |
*/ | |
interface Member { | |
name: string; | |
id: number; | |
} | |
/** | |
* Admins are users with a `permissions` property | |
*/ | |
interface Admin extends Member { | |
permissions: number; | |
} | |
/** | |
* An ImpersonatedMember is an Admin with their ID moved to the `adminID` property, so that the `id` | |
* property from Member can be used normally, pulled from the impersonated member | |
*/ | |
interface ImpersonatedMember extends Admin { | |
adminID: number; | |
} | |
/** | |
* Another example | |
*/ | |
interface FormControlInputs { | |
label: string; | |
onChange(): any; | |
} | |
type isTextValidator = (input: any) => boolean; | |
interface TextInput extends FormControlInputs { | |
placeholder: string; | |
validator: isTextValidator; | |
onChange(): string; // this is valid because `string` is a subset of `any` | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* We know that an API list returns a `results` array, but we don't know the type of that array ahead of time. | |
* To solve this, we make the list a generic type. In usage, this would look like `const response: ApiList<Claim> = ....` | |
*/ | |
interface ApiList<TListType> { | |
count: number; | |
next: number; | |
previous: number; | |
results: TListType[]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* In this example, assume ButtonConfig and DescriptionSectionConfig are config classes | |
* for reusable components. A page's config is really the config of it and what it contains | |
* so in this case, the types of multiple parts of a config can be merged together to create | |
* a single type | |
*/ | |
class ButtonConfig { | |
label: string; | |
spacing: 'small' | 'medium' | 'large'; | |
} | |
class DescriptionSectionConfig { | |
header: string; | |
contents: string; | |
} | |
class MyPageConfig { | |
someOtherProps: object; | |
} | |
type BestConfig = ButtonConfig & DescriptionSectionConfig & MyPageConfig; | |
const a: BestConfig = { | |
label: 'abc', | |
spacing: 'medium', | |
header: 'ermagerd', | |
contents: 'this is some text describing ermagerd', | |
someOtherProps: {}, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* In this situation all props are optional - this is virtually _never_ actually the case. As a result, this | |
* type does not convey any information about when `a`, `b` or `c` is actually present. What might be _actually_ | |
* the case is that `a` and `b` must be present together, otherwise `c` is present, in which case we have implicit | |
* rules about how this type works that must exist in _code_ rather than the actual definition of the data itself | |
*/ | |
interface NonExpressiveType { | |
a?: string; | |
b?: string; | |
c?: string; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A benefitValue can come back as a number, or pre-formatted as a string | |
* | |
* This is useful when the type is discernible at runtime (unlike object or array types | |
* which can only have their type determined at build time). If you need to discern | |
* between types of objects, it is preferable to use a `discriminated union` instead. | |
*/ | |
type benefitValue = number | string; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment