Basics - everyday types Flashcards
List TypeScript primitive types
Same as JavaScript primititve types: string
, number
, bigint
, undefined
, null
, boolean
and symbol
Source typescriptlang
How do you define an Array type in TypeScript?
To specify the type of an array like [1, 2, 3]
, you can use the syntax number[];
this syntax works for any type (e.g. string[]
is an array of strings, and so on). You may also see this written as Array<number>
, which means the same thing.
Source typescriptlang
Explain TypeScript special type any
?
Special type any
can be used whenever you don’t want a particular value to cause typechecking errors.
The any
type is useful when you don’t want to write out a long type just to convince TypeScript that a particular line of code is okay.
Source typescriptlang
Why should you NOT use any
type?
any
type is not type-checked. This means that TypeScript will consider valid a variable with any
type. No matter where it is used.
What’s worst is that the use of any
type is “contagious” in that it can quitely spread throughout a codebase removing the type safety that TypeScript provieds. For example:
function f1() { const x: any = expressionReturningFoo(); // Don’t do this processBar(x); return x } function g() { const foo = f1(); // Type is any foo.fooMethod(); // This call is unchecked! }
What type should you use instead of any
?
unknown
type
Explain TypeScript special type unknown
The unknown
type represents any value. This is similar to the any
type, but is safer because it’s not legal to do anything with an unknown
value:
function f1(a: any) { a.b(); // OK } function f2(a: unknown) { a.b(); // NOT OK: Object is of type 'unknown'. }
Source typescriptlang
How do you define a type anotation?
:type
after the name of the variable, parameter or property. There can be a space after the colon.
let myName: string = "Alice"; function(foo: string, bar: number) {}
Note: TypeScript doesn’t use “types on the left”-style declarations like int x = 0; Type annotations will always go after the thing being typed.
Source typescriptlang
How do you define the return type of a declared function?
Adding the return type after the parameter list with a colon :
function getFavoriteNumber(): number { return 26; }
Source typescriptlang
How do you define an object type?
To define an object type
, we simply list its properties and their types.
For example, here’s a function that takes a point-like object:
// The parameter's type annotation is an object type function printCoord(pt: { x: number; y: number }) { console.log("The coordinate's x value is " + pt.x); console.log("The coordinate's y value is " + pt.y); } printCoord({ x: 3, y: 7 });
Source typescriptlang
How do you define an optional property on an object type?
Adding a ?
after the property name:
function printName(obj: { first: string; last?: string }) { // ... } // Both OK printName({ first: "Bob" }); printName({ first: "Alice", last: "Alisson" });
Source typescriptlang
What is a union type?
A union type is a type formed from two or more other types, representing values that may be any one of those types.
We refer to each of these types as the union’s members.
Example:
function printId(id: number | string) { console.log("Your ID is: " + id); } printId(101); // OK printId("202"); // OK printId({ myID: 22342 }); // NOT OK // Throws Error `Argument of type '{ myID: number; }' is not assignable to parameter of type 'string | number'`.
Source typescriptlang
How can you narrow the type of a union type?
Narrowing occurs when TypeScript can deduce a more specific type for a value based on the structure of the code.
For example, TypeScript knows that only a string
value will have a typeof
value "string"
:
function printId(id: number | string) { if (typeof id === "string") { // In this branch, id is of type 'string' console.log(id.toUpperCase()); } else { // Here, id is of type 'number' console.log(id); } }
Another example is to use a function like Array.isArray:
function welcomePeople(x: string[] | string) { if (Array.isArray(x)) { // Here: 'x' is 'string[]' console.log("Hello, " + x.join(" and ")); } else { // Here: 'x' is 'string' console.log("Welcome lone traveler " + x); } }
Source typescriptlang
What are Type Aliases?
A type
alias is exactly that - a name for any type. The syntax for a type alias is:
type Point = { x: number; y: number; }; function printCoord(pt: Point) { console.log("The coordinate's x value is " + pt.x); console.log("The coordinate's y value is " + pt.y); }
You can actually use a type alias to give a name to any type at all. Primitive types, objects, union types, etc.
Source typescriptlang
What is an Interface Declaration?
An interface declaration is one of the ways you can name an object type in TypeScript (type aliases are another way)
interface Point { x: number; y: number; } function printCoord(pt: Point) { console.log("The coordinate's x value is " + pt.x); console.log("The coordinate's y value is " + pt.y); }
Source typescriptlang
What are the differences between Type Aliases and Interfaces?
- An
interface
can be extended with theextends
keyword and atype
can not. - Type alias names may appear in error messages, sometimes in place of the equivalent anonymous type (TypeScript version 4.2 or less). Interfaces will always be named in error messages.
- Type aliases may not participate in declaration merging, but interfaces can.
- Interfaces may only be used to declare the shapes of objects, not rename primitives.
- Interface names will always appear in their original form in error messages, but only when they are used by name.
Source typescriptlang
What is a type assertion?
Sometimes you will have information about the type of a value that TypeScript can’t know about.
For example, if you’re using document.getElementById
, TypeScript only knows that this will return some kind of HTMLElement
, but you might know that your page will always have an HTMLCanvasElement
with a given ID.
In this situation, you can use a type assertion to specify a more specific type:
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
You can also use the angle-bracket syntax (except if the code is in a .tsx
file), which is equivalent:
const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");
Source typescriptlang
Why does TypeScript only allows type assertions which convert to a more specific or less specific version of a type?
To prevent “impossible” coercions like:
const x = "hello" as number; // Error: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Sometimes this rule can be too conservative and will disallow more complex coercions that might be valid. If this happens, you can use two assertions, first to unknown
or any
, then to the desired type:
const a = (expr as unknown) as T;
Source typescriptlang
What are literal types?
Literal types refer to specific strings and numbers in type positions.
let x: "hello" = "hello"; // OK x = "hello"; // OK x = "howdy"; // Error: Type '"howdy"' is not assignable to type '"hello"'.
Source typescriptlang
What is literal inference
When you initialize a variable with an object, TypeScript assumes that the properties of that object might change values later.
For example:
const req = { url: "https://example.com", method: "GET" }; handleRequest(req.url, req.method); // Error: Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.
In the above example req.method
is inferred to be string
, not "GET"
. Because code can be evaluated between the creation of req
and the call of handleRequest
which could assign a new string like "GUESS"
to req.method
, TypeScript considers this code to have an error.
There are two ways to work around this.
- You can change the inference by adding a type assertion in either location:
// Change 1: const req = { url: "https://example.com", method: "GET" as "GET" }; // Change 2 handleRequest(req.url, req.method as "GET");
- You can use
as const
to convert the entire object to be type literals:
const req = { url: "https://example.com", method: "GET" } as const; handleRequest(req.url, req.method);
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.
Source typescriptlang
How does null
and undefined
behave when compiler option strictNullChecks
is off?
With strictNullChecks off, values that might be null
or undefined
can still be accessed normally, and the values null
and undefined
can be assigned to a property of any type. This is similar to how languages without null checks (e.g. C#, Java) behave. The lack of checking for these values tends to be a major source of bugs.
Source typescriptlang
How does null
and undefined
behave when compiler option strictNullChecks
is on?
With strictNullChecks on, when a value is null
or undefined
, you will need to test for those values before using methods or properties on that value. Just like checking for undefined
before using an optional property, we can use narrowing to check for values that might be null
:
function doSomething(x: string | null) { if (x === null) { // do nothing } else { console.log("Hello, " + x.toUpperCase()); } }
Source typescriptlang
What does the Non-null Assertion Operator (Postfix !
) do?
TypeScript has a special syntax for removing null
and undefined
from a type without doing any explicit checking. Writing !
after any expression is effectively a type assertion that the value isn’t null
or undefined
:
function liveDangerously(x?: number | null) { // No error console.log(x!.toFixed()); }
Just like other type assertions, this doesn’t change the runtime behavior of your code, so it’s important to only use !
when you know that the value can’t be null
or undefined
.
Source typescriptlang
What is the BigInt
primitive
bigint
(all lowercase) is a new type of primitive. You can get a bigint
by calling the BigInt()
function or by writing out a BigInt literal by adding an n
to the end of any integer numeric literal:
let foo: bigint = BigInt(100); // the BigInt function let bar: bigint = 100n; // a BigInt literal
number
and bigint
, are separate domains. As specified in ECMAScript, mixing numbers and bigints in arithmetic operations is an error. You’ll have to explicitly convert values to BigInts.
Also important to note is that bigints produce a new string when using the typeof
operator: the string "bigint"
. Thus, TypeScript correctly narrows using typeof as you’d expect.
Source typescriptlang
What is the Symbol
primitive
symbol
(all lowercase) is a new primitive data type, just like number
and string
.symbol
values are created by calling the Symbol
constructor.
let sym1 = Symbol(); let sym2 = Symbol("key"); // optional string key
Symbols are immutable, and unique.
let sym2 = Symbol("key"); let sym3 = Symbol("key"); sym2 === sym3; // false, symbols are unique
Just like string
s, symbol
s can be used as keys for object properties.
const sym = Symbol(); let obj = { [sym]: "value", }; console.log(obj[sym]); // "value"
Also important to note is that symbol
s produce a new string when using the runtime typeof
operator: the string "symbol"
. Thus, TypeScript correctly narrows using typeof as you’d expect.
Source typescriptlang
What is a unique symbol
?
unique symbol
is a subtype of symbol
, and are produced only from calling Symbol()
or Symbol.for()
, or from explicit type annotations. This type is only allowed on const
declarations and readonly static
properties.
In order to reference a specific unique symbol, you’ll have to use the typeof
type operator. Each reference to a unique symbol implies a completely unique identity that’s tied to a given declaration.
declare const sym1: unique symbol; // sym2 can only be a constant reference. let sym2: unique symbol = Symbol(); // Error: A variable whose type is a 'unique symbol' type must be 'const'. // Works - refers to a unique symbol, but its identity is tied to 'sym1'. let sym3: typeof sym1 = sym1; // Also works. class C { static readonly StaticSymbol: unique symbol = Symbol(); }
Note: unique symbol
is a subtype of symbol
type. It allows you to replicate the behaviour of string
literals with symbols
.
Source typescriptlang