banner
小凯同学 xkfe

小凯同学 xkfe

学而不思则罔,思而不学则殆
twitter
github
email

TypeScript High-Frequency Interview Questions/Writing

What is an interface?#

// 1. Define object structure
interface Car {
  brand: string;
  speed: number;
  drive(): void;
}
let myCar: Car = {
  brand: "Toyota",
  speed: 120,
  drive() {
    console.log("Driving at speed: " + this.speed);
  }
};

// 2. Specify interface as read-only and optional
interface Point {
  readonly x: number; // read-only
  readonly y: number; // read-only
  z?: number;  // optional
}
let p1: Point = { x: 10, y: 20 };

What is the difference between type and interface?#


What is the difference between unknown and any?#

let value: unknown;
value = 42;
// Type checking is required before calling the `toFixed` method
if (typeof value === "number") {
  value.toFixed(); // Correct
}

value = "Hello";
// Type checking is required before calling the `toUpperCase` method
if (typeof value === "string") {
  value.toUpperCase(); // Correct
}

What is the usage of the never type?#

// Throwing an exception
function throwError(message: string): never {
  throw new Error(message);
}

// Infinite loop
function infiniteLoop(): never {
  while (true) {
    // Infinite loop, will never return
  }
}

// Exhaustive check
type Shape = 'circle' | 'square';

function getArea(shape: Shape): number {
  switch (shape) {
    case 'circle':
      return Math.PI * 1 ** 2;
    case 'square':
      return 1 * 1;
    default:
      const _exhaustiveCheck: never = shape; // Here, `shape` will never be any other value
      throw new Error(`Unexpected shape: ${shape}`);
  }
}

What is the difference between never and void?#

function logMessage(message: string): void {
  console.log(message); // This function returns `undefined`
}

function throwError(message: string): never {
  throw new Error(message); // This function will never return
}

Discuss union types, intersection types, type aliases, and type guards.#

Union Types#

  • Union types allow a variable to be one of several types. Defined using the | (pipe) symbol.
  • Scenario: Used to represent a value that can be one of several different types, such as a function parameter that can accept multiple types of data.
let value: string | number;

function formatInput(input: string | number): string {
  if (typeof input === "string") {
    return input.toUpperCase();
  } else {
    return input.toFixed(2);
  }
}

Intersection Types#

  • Intersection types combine multiple types into one type, which has all the features of the combined types. Defined using & (ampersand).
  • Scenario: Used to combine properties of multiple types to create an object type that has all properties.
interface Person {
  name: string;
}
interface Employee {
  id: number;
}
let employee: Person & Employee = {
  name: "Alice",
  id: 123
};

function printEmployee(employee: Person & Employee) {
  console.log(`Name: ${employee.name}, ID: ${employee.id}`);
}

Type Aliases#

  • Type aliases create a new name (alias) for a type. Defined using the type keyword, suitable for basic types, union types, intersection types, etc.
  • Scenario: Used to simplify complex types and improve code readability. It can create simple aliases for complex types like objects, functions, union types, etc.
type ID = string | number;
let userId: ID = "abc123";

type User = {
  name: string;
  age: number;
};
function greet(user: User) {
  console.log(`Hello, ${user.name}`);
}

Type Guards#

Type guards are a technique in TypeScript used to determine the actual type of a value and perform further processing based on that type. They are very useful when using union types to ensure that the correct operations are performed in different type branches.

  1. typeof Type Guard: Used to check basic types (string, number, boolean, etc.)
function printId(id: string | number) {
  if (typeof id === "string") {
    console.log(id.toUpperCase());
  } else {
    console.log(id.toFixed(2));
  }
}
  1. instanceof Type Guard: Used to check if an object is an instance of a certain class.
class Dog {
  bark() {
    console.log("Woof!");
  }
}
class Cat {
  meow() {
    console.log("Meow!");
  }
}
function makeSound(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    animal.bark();
  } else {
    animal.meow();
  }
}
  1. is Keyword: You can create custom type guards by returning a value of type is from a function.
function isString(value: any): value is string {
  return typeof value === "string";
}

function printValue(value: string | number) {
  if (isString(value)) {
    console.log(value.toUpperCase());
  } else {
    console.log(value.toFixed(2));
  }
}
  1. in Keyword: Used to check if an object has a certain property, especially when checking object types in union types.
interface Bird {
  fly(): void;
}
interface Fish {
  swim(): void;
}
function move(animal: Bird | Fish) {
  if ("fly" in animal) {
    animal.fly();
  } else {
    animal.swim();
  }
}

What is the purpose of the typeof keyword?#

// 1. Reuse existing variable types
let person = {
  name: "Alice",
  age: 25,
};
type PersonType = typeof person; // { name: string; age: number; }

// 2. Function return types
function getPerson() {
  return { name: "Alice", age: 25 };
}

type PersonType = typeof getPerson(); // { name: string; age: number; }

// 3. Type checking in JavaScript
function printValue(value: number | string) {
  if (typeof value === "string") {
    console.log("This is a string: ", value);
  } else {
    console.log("This is a number: ", value);
  }
}

What is the purpose of the keyof keyword?#

// 1. Get keys of an object type
type Person = {
  name: string;
  age: number;
  location: string;
};

type PersonKeys = keyof Person; // 'name' | 'age' | 'location'

// 2. Type constraints (key must be a key of obj)
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
const person = { name: "Alice", age: 25, location: "NYC" };
const name = getValue(person, "name");
const age = getValue(person, "age");

How to define an enum? What are the usage scenarios?#

enum ResultEnum {
  SUCCESS = 200,
  ERROR = 500,
  NOTLOGGED = 401,
  OVERDUE = 402,
  TIMEOUT = 5000,
}

enum LogLevel {
  Info,
  Warn,
  Error
}

How to union enum type keys?#

enum Direction {
  Up,
  Down,
  Left,
  Right
}

type DirectionType = keyof typeof Direction; // Up | Down | Left | Right

What are generics?#

// Simple generic function
function echo<T>(arg: T): T {
  return arg;
}
echo<number>(42); // Passing number type

// Generic interface
interface Box<T> {
  content: T;
}

// Default generic type
function createArray<T = string>(length: number, value: T): T[] {
  return Array(length).fill(value);
}

How to constrain generic types?#

Specify that generic parameters must meet certain conditions, such as having certain properties or methods.

interface Lengthwise {
  length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}
logLength("Hello"); // String has length property, valid
// logLength(123); // This will cause an error because number type does not have length property

What is the purpose of as? When to use it?#

let someValue: any = "This is a string";

// We know someValue is of string type
let strLength: number = (someValue as string).length;

let colors = ["red", "green", "blue"] as const;
// `colors` type will be readonly ["red", "green", "blue"]

What is a tuple? How does it differ from a TypeScript array?#

let tuple: [string, number];
tuple = ["Hello", 42]; // Valid
// tuple = [42, "Hello"]; // Invalid, order error
function getUserInfo(): [string, number] {
  return ["Alice", 25];
}

let entry: [string, number] = ["score", 100];
console.log(entry[0]); // Outputs "score"

// Tuples with optional elements
type FlexibleTuple = [string, number?, boolean?];
let tuple1: FlexibleTuple = ["Hello"];

What is function overloading? What is its purpose?#

// Overload signatures (without implementation)
function format(input: number): string;
function format(input: Date): string;

// Implementation signature (contains logic)
function format(input: any): string {
  if (typeof input === "number") {
    return input.toFixed(2); // Format number
  } else if (input instanceof Date) {
    return input.toISOString(); // Format date
  }
}

// Different number and type of parameters
function greet(name: string): string;
function greet(firstName: string, lastName: string): string;

function greet(firstName: string, lastName?: string): string {
  if (lastName) {
    return `Hello, ${firstName} ${lastName}!`;
  } else {
    return `Hello, ${firstName}!`;
  }
}

How to implement conditional types?#

Conditional types are typically written in the form T extends U ? X : Y, where T extends U indicates a condition check; if the condition is true, it returns type X, otherwise it returns type Y. This is similar to the ternary operator in JavaScript condition ? trueValue : falseValue.

T extends U ? X : Y
// • T extends U: Indicates the condition, checking if type T can be assigned to type U.
// • X: The type returned when T satisfies the condition (i.e., T extends U is true).
// • Y: The type returned when T does not satisfy the condition (i.e., T extends U is false).

// Example:
type IsString<T> = T extends string ? "Yes" : "No";

type A = IsString<string>;  // "Yes"
type B = IsString<number>;  // "No"

What are some commonly used built-in utility types?#

Partial<T>#

Makes all properties of type T optional.

interface Person {
  name: string;
  age: number;
}

type PartialPerson = Partial<Person>;
// PartialPerson is equivalent to { name?: string; age?: number; }

Required<T>#

Makes all properties of type T required.

interface Person {
  name?: string;
  age?: number;
}

type RequiredPerson = Required<Person>;
// RequiredPerson is equivalent to { name: string; age: number; }

Readonly<T>#

Makes all properties of type T readonly, preventing modification.

interface Person {
  name: string;
  age: number;
}

type ReadonlyPerson = Readonly<Person>;
// ReadonlyPerson is equivalent to { readonly name: string; readonly age: number; }

Pick<T, K>#

Creates a new type by picking certain properties from type T. K is a union type of the properties to pick.

interface Person {
  name: string;
  age: number;
  address: string;
}

type PersonNameAndAge = Pick<Person, "name" | "age">;
// PersonNameAndAge is equivalent to { name: string; age: number; }

Omit<T, K>#

Constructs a new type by omitting properties specified by K from type T.

interface Person {
  name: string;
  age: number;
  address: string;
}

type PersonWithoutAddress = Omit<Person, "address">;
// PersonWithoutAddress is equivalent to { name: string; age: number; }

Record<K,T>#

Constructs a type where keys K can be strings, numbers, etc., and values T are the types of all properties.

type Page = "home" | "about" | "contact";
type PageInfo = { title: string };

const pages: Record<Page, PageInfo> = {
  home: { title: "Home Page" },
  about: { title: "About Us" },
  contact: { title: "Contact Us" },
};

Exclude<T,U>#

Excludes all subtypes of type U from union type T.

type A = "a" | "b" | "c";
type B = "a";

type Result = Exclude<A, B>; // "b" | "c"

Extract<T,U>#

Extracts all subtypes from union type T that can be assigned to type U.

type A = "a" | "b" | "c";
type B = "a" | "b";

type Result = Extract<A, B>; // "a" | "b"

NonNullable<T>#

Excludes null and undefined from type T.

type A = string | null | undefined;

type NonNullableA = NonNullable<A>; // string

ReturnType<T>#

Gets the return type of function type T.

function getUser() {
  return { name: "Alice", age: 25 };
}

type UserType = ReturnType<typeof getUser>;
// UserType is equivalent to { name: string; age: number; }

InstanceType<T>#

Gets the instance type of constructor function type T.

class Person {
  name: string = "Alice";
  age: number = 25;
}

type PersonInstance = InstanceType<typeof Person>;
// PersonInstance is equivalent to Person

Parameters<T>#

Gets the parameter types of function type T, returning a tuple type.

function greet(name: string, age: number): string {
  return `Hello ${name}, you are ${age} years old.`;
}

type GreetParams = Parameters<typeof greet>;
// GreetParams is equivalent to [string, number]

ConstructorParameters<T>#

Gets the parameter types of constructor function type T, returning a tuple type.

class Person {
  constructor(public name: string, public age: number) {}
}

type PersonConstructorParams = ConstructorParameters<typeof Person>;
// PersonConstructorParams is equivalent to [string, number]

ThisType<T>#

Used to specify the type of the context object this, usually used in conjunction with the noImplicitThis option.

type ObjectDescriptor<D, M> = {
  data?: D;
  methods?: M & ThisType<D & M>; // this in M will be inferred as D & M type
};

let obj: ObjectDescriptor<{ x: number }, { foo(): void }> = {
  data: { x: 10 },
  methods: {
    foo() {
      console.log(this.x); // Inferred as number
    }
  }
};

Awaited<T>#

Gets the resolved type of a Promise.

type P = Promise<string>;

type Result = Awaited<P>; // string

What are declare and declare global?#

What is the difference between .d.ts and .ts files?#

How to annotate types for component template instance references?#

<template>
  <MyComponent ref="myComponentRef" message="Hello, World!" />
</template>

<script setup lang="ts">
  import { ref } from 'vue'
  import MyComponent from './MyComponent.vue';
  const myComponentRef = ref<InstanceType<typeof MyComponent> | null>(null)
</script>

Explanation of typescript.json configuration!#

https://typescript.p6p.net/typescript-tutorial/tsconfig.json.html#compileoptions

{
  // Compilation options
  "compilerOptions": {
    // Specify ECMAScript target version (e.g., ES5, ES6, ESNext).
    "target": "ES6",
    // Specify the module system to use
    "module": "ESNext", 
    // Enable all strict type checking options.
    "strict": true,
    // Enable interoperability support for ES modules.
    "esModuleInterop": true,
    // Generate .map files for debugging.
    "sourceMap": true,
    // Specify the compilation method for JSX code (e.g., react, react-jsx, preserve).
    "jsx": "preserve",
    // Specify the library files to use (e.g., DOM, ES6, ESNext).
    "lib": ["ES6", "DOM"],
    // Specify the library files to use (e.g., DOM, ES6, ESNext).
    "skipLibCheck": true,
    // Prohibit implicit any types without type annotations.
    "noImplicitAny": true,
    // Generate declaration files; will automatically generate declaration files when enabled.
    "declaration": true,
    // Specify the directory to store declaration files
    "declarationDir": "./file",
    // Only generate declaration files, without generating js files
    "emitDeclarationOnly": true,
    // Allow export= exports to be imported using import from
    "esModuleInterop": true,
    // Resolve the base URL for non-relative modules, default is the current directory
    "baseUrl": "./",
    // Path mapping, relative to baseUrl
    "paths": { 
       "@/*": ["./src/*"]
    },
    // ...
  },
  // Included files or directories
  "include": [],
  // Excluded files or directories
  "exclude": [],
  // Specify a specific list of files to compile, suitable for small projects.
  "files": [],
  // Used to support project references, suitable for large projects.
  "references": []
  // Inherit other configurations
  "extends": ""
}
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.