Last active
February 11, 2021 20:50
-
-
Save hatemhosny/4bed283ef9757a6a541aee685c710dc7 to your computer and use it in GitHub Desktop.
Compiled Code
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
// TypeScript's inference can get you very far, but there | |
// are lots of extra ways to provide a richer way to document | |
// the shape of your functions. | |
// A good first place is to look at optional params, which | |
// is a way of letting others know you can skip params. | |
let i = 0; | |
const incrementIndex = (value?: number) => { | |
i += value === undefined ? 1 : value; | |
}; | |
// This function can be called like: | |
incrementIndex(); | |
incrementIndex(0); | |
incrementIndex(3); | |
// You can type parameters as functions, which provides | |
// type inference when you write the functions. | |
const callbackWithIndex = (callback: (i: number) => void) => { | |
callback(i); | |
}; | |
// Embedding function interfaces can get a bit hard to read | |
// with all the arrows. Using a type alias will let you name | |
// the function param. | |
type NumberCallback = (i: number) => void; | |
const callbackWithIndex2 = (callback: NumberCallback) => { | |
callback(i); | |
}; | |
// These can be called like: | |
callbackWithIndex(index => { | |
console.log(index); | |
}); | |
// By hovering on index above, you can see how TypeScript | |
// has inferred the index to be a number correctly. | |
// TypeScript inference can work when passing a function | |
// as an instance reference too. To show this, we'll use | |
// a function which changed a number into string: | |
const numberToString = (n: number) => { | |
return n.toString(); | |
}; | |
// This can be used in a function like map on an array | |
// to convert all numbers into a string, if you hover | |
// on stringedNumbers below you can see the expected types. | |
const stringedNumbers = [1, 4, 6, 10].map(i => numberToString(i)); | |
// We can use shorthand to have the function passed directly | |
// and get the same results with more focused code: | |
const stringedNumbersTerse = [1, 4, 6, 10].map(numberToString); | |
// You may have functions which could accept a lot of types | |
// but you are only interested in a few properties. This is | |
// a useful case for indexed signatures in types. The | |
// following type declares that this function is OK to use | |
// any object so long as it includes the property name: | |
interface AnyObjectButMustHaveName { | |
name: string; | |
[key: string]: any; | |
} | |
const printFormattedName = (input: AnyObjectButMustHaveName) => {}; | |
printFormattedName({ name: "joey" }); | |
printFormattedName({ name: "joey", age: 23 }); | |
// If you'd like to learn more about index-signatures | |
// we recommend: | |
// | |
// https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks | |
// https://basarat.gitbooks.io/typescript/docs/types/index-signatures.html | |
// You can also allow this kind of behavior everywhere | |
// via the tsconfig flag suppressExcessPropertyErrors - | |
// however, you can't know if others using your API have | |
// this set to off. | |
// Functions in JavaScript can accept different sets of params. | |
// There are two common patterns for describing these: union | |
// types for parameters/return, and function overloads. | |
// Using union types in your parameters makes sense if there | |
// are only one or two changes and documentation does not need | |
// to change between functions. | |
const boolOrNumberFunction = (input: boolean | number) => {}; | |
boolOrNumberFunction(true); | |
boolOrNumberFunction(23); | |
// Function overloads on the other hand offer a much richer | |
// syntax for the parameters and return types. | |
interface BoolOrNumberOrStringFunction { | |
/** Takes a bool, returns a bool */ | |
(input: boolean): boolean; | |
/** Takes a number, returns a number */ | |
(input: number): number; | |
/** Takes a string, returns a bool */ | |
(input: string): boolean; | |
} | |
// If this is your first time seeing declare, it allows you | |
// to tell TypeScript something exists even if it doesn't | |
// exist in the runtime in this file. Useful for mapping | |
// code with side-effects but extremely useful for demos | |
// where making the implementation would be a lot of code. | |
declare const boolOrNumberOrStringFunction: BoolOrNumberOrStringFunction; | |
const boolValue = boolOrNumberOrStringFunction(true); | |
const numberValue = boolOrNumberOrStringFunction(12); | |
const boolValue2 = boolOrNumberOrStringFunction("string"); | |
// If you hover over the above values and functions you | |
// can see the right documentation and return values. | |
// Using function overloads can get you very far, however | |
// there's another tool for dealing with different types of | |
// inputs and return values and that is generics. | |
// These provide a way for you to have types as placeholder | |
// variables in type definitions. | |
// example:generic-functions | |
// example:function-chaining |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment