Last active
January 30, 2023 10:14
-
-
Save angelikatyborska/cea5696595be44b930498bfd5e124454 to your computer and use it in GitHub Desktop.
TypeScript notes
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
// If I define a union type of strings and want to use it as a type for object keys: | |
type Food = 'Banana' | 'Berries' | |
const calorieCounts: { [index in Food]: number } = {} // <- NOT `index: Food` | |
// ---------- | |
// If I define an object and want to use its keys as a type: | |
// NOTE the object shouldn't have a type definition for this to work! | |
const planetYearsToEarthYears = { earth: 1, mercury: 0.24 } | |
type Planet = keyof typeof planetYearsToEarthYears | |
// ---------- | |
// Official TS docs recommend to use Interface over Type | |
// https://www.typescriptlang.org/play?&e=83#code/PTAEBUAsFMCdtAQ3qALgdwPagLaIJYB2ammANgM4mgAm0AxmcgqjKBZIgA4KYBmSQgFgAUCFCYARgCsGqAFygiqOH0T1oVRIRpoAnjyRl8iCpoB0okFbBRoepCgBucBxXw58TWABpBuvkxYNDYcTApUUHpMHDDielNNGyR6SNYECkQcaEsRUVQDBAAhfFgacELQAF5QAG9RUFB0IgBzCkUAJgBuUQBfHryRZVV1YtKaAElCFVg1DTqGptb20G6+0VFowgjQSXGARkUSsorDGtqlwjbO0H7NzG3IvbKOo-GpmbmEc8vr1duBskigxEABXMwQQoAZXosHwXEi+C07FQsFBqVBsEQZH0hgoegi0BwPmS+FQAHIqFxwu5JGQWNhhrBPAAPELQUqgcEMzC5e6PXbjADMbzKHxG8xqzxo+0BYlsMAckkwrHYoK41NgkWgLJUOlaEnSwSZXy0OlxFmSpwQ2JMZioNGwrCRoCcJiU0zgZlS+AeFoofnQkC80FJntmoyonBcSFAAGt7FgynyRAVDAB5dA4n6ETAY2CEbGKVGghC9UAAMlAx3KhQGaYQACUpERqnVQLn84WyIo1JQy5Xq+9w185SbRqAAArQdR5uOgHV6mhUGvWhYiRrRMiYTF8UE9tBo6ADRp8YyaXvYswDXqicfzADCwfoCeIi+gOhXw8+E-qG6i5A7rM+6Xv2J6gGe+AXhBV7Husgz0pEmBZoombZu2zRXCsHR+J2qCYt2xZHgCoiIVEz6vooT74C+H5thcmF-DhAHbruIEwf2fiQdBfYQncgziFAiCRJk+A0IGCDwNEsQfroeg7lyEL3poEguMEDbJLaiQUOYoBQjw9D4HwNHYmQeh+JIILcqA8mgksZA4i00BPM5MwLrAsBBMk2QUJkTk6aAEwCLZoCQJgamqXA7IQeQ26Me5nmwAGNkKQkwjyuw0AIGF6CQjwMJwgiUTaKAXCeW6dBoF6UXaLoYQoIE9DcjQ3maH5KlBnRSZxgazSqspVDGAmoDUbRhApsh6H0BRH4DNNNGvm2k1yuI6aEAgeDSEEtBGXwcAfvMlkYFlxANkYdoqU4VADZpKCsMJHo-hoWgoJgPDELVFrndpjgIIw4TQDQuSCcGVDZNoVAhWlC66rJgiPRKCCSA4dCMMgBpkppmVbLoqAeDkGxDCOE4ANJknq66NFwmJJYoyrkDOhA3oTymgGTqAU3+m6AZiigRHCVzMwJYBTNFKowMECQQogX1pbmLnkdoTm6DuqDuJV-CkmrtAMN4wm+uNhNnZO6pcA45yLFuQR86irQ3nKxum+blMkASiiEKCOCWbA9uE+IAAi0DvTQBp+rZwQtJgV5+M6Dq7fthDzNE+66JZSDJNS7h4zG20y+tLT6y4ukABLIdAEWBME1N0jRZkw5ngPJA2yVkpSsZHW5CQOdQeDDekODw8pKaretEgCOkuyaJE8AUEBz0xcEZgclcRg4vw0WA05yRSypyA7uazeutdxPPTHoMouo87haocVN5A8CILoLoy5HmC6FwTDzKg2ARMgCh+2ASAHMuDtBAL-F819ZhxXMNJYAABHUsEQDYUGAEKAA7B0IU6ChQAFZgDN1hPCVAABaAaxCrrEObsAHBHQABsAAODoTCAAMABiGhDCmEdGYaIIAA | |
// ---------- | |
// > The `as const` suffix acts like const but for the type system, | |
// > ensuring that all properties are assigned the literal type instead of a more general version like string or number. | |
const req = { url: "https://example.com", method: "GET" } as const; | |
// ---------- | |
// `in` is for checking keys in objects, not for arrays! | |
> 'x' in {x: 31, y: 23} | |
true | |
> 'x' in ['x', 'y'] | |
false | |
> ['x', 'y'].includes('x') | |
true | |
// ---------- | |
// how to overload type definitions for one function | |
// (e.g. if given argument of type X, returns type A, if given argument of type Y, returns type B) | |
function plusOne(x: string): string; | |
function plusOne(x: number): number; | |
function plusOne(x: string | number) { // <- DO NOT define return type here | |
if (typeof x === 'number') { | |
return x + 1 | |
} else { | |
return `${x} plus one` | |
} | |
} | |
// (correct TS, but might break some eslint rules like no-redeclare and @typescript-eslint/explicit-function-return-type :<) | |
// ---------- | |
// `never` appears when TypeScript determines there’s nothing left in a union. | |
function fn(x: string | number) { | |
if (typeof x === "string") { | |
// do something | |
} else if (typeof x === "number") { | |
// do something else | |
} else { | |
x; // has type 'never'! | |
} | |
} | |
// ---------- | |
// object properties can be marked as readonly, but | |
// TypeScript doesn’t factor in whether properties on two types are readonly | |
// when checking whether those types are compatible | |
interface SomeType { | |
readonly prop: string; | |
} | |
// ---------- | |
// you can define an interface with both known and unknown keys of known types | |
interface NumberOrStringDictionary { | |
[index: string]: number | string; | |
length: number; // ok, length is a number | |
name: string; // ok, name is a string | |
} | |
// ---------- | |
// tuples are arrays of known length | |
type StringNumberPair = [string, number]; | |
type Either2dOr3d = [number, number, number?]; | |
// ---------- | |
// hints for using React with TS: | |
// https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/basic_type_example | |
// ---------- | |
// Types for React refs: | |
// - `MutableRefObject<T>` if you yourself assign to `ref.current` | |
// - `RefObject<T>` if you let React handle assignment | |
// | |
// In both cases, initial value of null as allowed even if T doesn't cover null | |
// ---------- | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@mtarnovan
I have been talking here about compile time checks only, no runtime stuff. It can work. TypeScript does a lot of static code analysis to narrow down types. See this modified example, with reloaded function signatures, where I make one of the return values have a type that doesn't fulfill the signature:
It produces this error:
Yes! But I literally never used
in
in JavaScript, and as it started appearing in TypeScript for type definitions and type guards, I got confused 😵