Happylab Logo
Published on

Day05: Learning TypeScript - Three Methods for Specifying Types

Authors

Day05: Learning TypeScript - Three Methods for Specifying Types


In TypeScript, there are three methods to specify types: Type Inference, Type Annotation, and Type Assertions.


Type Inference

If a type is not explicitly specified, TypeScript will infer a type based on its rules. For example, x will be inferred as a number type. If x is later assigned a string type, it will throw an error.

let x = 3
x = 'hello' // error: Type 'number' is not assignable to type 'string'.


Type Annotation

In addition to automatic type inference, TypeScript allows us to manually specify types, making it easier to debug when assigning values to variables.

You can use : after the variable name. In the example below, the age variable is specified as a number type, so assigning a string type "32" will throw an error.

let age: number = 18 // number variable
let person: string = 'iris' // string variable
let isUpdated: boolean = true // boolean variable

age = '32' // error: Type 'string' is not assignable to type 'number'.
isUpdated = false // ok

console.log(age) // 18
console.log(person) // iris
console.log(isUpdated) // false

Type Assertions

Sometimes you know the data type you want better than TypeScript does. TypeScript allows you to override its inference, but you should use this cautiously.

In the following example, the variable obj is inferred as {}, which has no properties, so you cannot add age or name properties.

let obj = {}
obj.age = 18 // error: property 'age' does not exist on `{}`
obj.name = 'iris' // error: property 'name' does not exist on `{}`

If you want to add properties, you can use assertions to specify the type, with two syntax options:

// Using an interface to define the object's type (which will be discussed later)
interface Foo {
  age: number
  name: string
}

// Syntax 1: Value as Type
const obj2 = {} as Foo
obj2.age = 18
obj2.name = 'iris'

const obj3 = {
  age: 18,
  name: 'iris',
} as Foo

// Syntax 2: <Type>Value
const obj4 = <Foo>{
  age: 18,
  name: 'iris',
}

console.log('assertions-as', obj2) // { age: 18, name: 'iris' }
console.log('assertions-as', obj3) // { age: 18, name: 'iris' }
console.log('assertions-<type>', obj4) // { age: 18, name: 'iris' }

Syntax

Value as Type
<Type>Value

⚠ These two syntaxes have the same effect, but in tsx syntax (the TypeScript version of JSX), you must use the latter (as) because JSX syntax uses <div> <span> <Xxxx> and using <Type>Value can reduce readability or cause confusion.

Use Assertions Cautiously

  1. If you don't add properties according to the convention, TS won't throw an error.
interface Foo {
  age: number
  name: string
}

const foo = {} as Foo

// Ahh, what did I forget? I didn't add properties, and there's no error reminder. If I miss a property, there won't be an error either.
  1. If the interface is refactored, it can easily lead to assertion errors.
interface Foo {
  age: number
  name: string
}

const foo = <Foo>{
  // The compiler will provide code hints about Foo properties
  // However, developers can easily forget to add all properties
  // Similarly, if Foo is refactored, this code may break (e.g., a new property is added).
}
  1. It's recommended to use better methods.
interface Foo2 {
  age: number
  name: string
}

const foo2: Foo2 = {
  // The compiler will provide code hints for Foo2 properties, missing age and name will throw an error.
}


In the next article, I will finally take notes on TypeScript data types! Looking forward to it. See you in the next article!

References

https://basarat.gitbook.io/typescript/type-system/type-assertion https://jkchao.github.io/typescript-book-chinese/typings/typeAssertion.html#%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80%E8%A2%AB%E8%AE%A4%E4%B8%BA%E6%98%AF%E6%9C%89%E5%AE%B3%E7%9A%84