Example 1
ts
let age = 38age = Number.NaN
Click here for the answer
Yes, this will compile. Unfortunately, obviously NaN
is a number in JavaScript.
tsTry
letage = 38age =Number .NaN
Example 2
ts
const vector3: [number, number, number] = [3, 4, 5]vector3.push(6)
Click here for the answer
Yes, this will compile. Unfortunately, because tuples are a specialized flavor
of arrays (and at runtime, they actually are just regular arrays) they expose the
entire array API. Look at the type signature of .push()
tsTry
constvector3 : [number, number, number] = [3, 4, 5]vector3 .push (6)
Example 3
ts
type Color = {red: numbergreen: numberblue: number}interface Color {alpha: number}
Click here for the answer
No, this will not compile.
tsTry
typeDuplicate identifier 'Color'.2300Duplicate identifier 'Color'.= { Color red : numbergreen : numberblue : number}interfaceDuplicate identifier 'Color'.2300Duplicate identifier 'Color'.{ Color alpha : number}
Example 4
ts
class Person {name: stringfriends: Person[]constructor(name: string) {this.name = name}}
Click here for the answer
No, this will not compile.
tsTry
classPerson {name : stringProperty 'friends' has no initializer and is not definitely assigned in the constructor.2564Property 'friends' has no initializer and is not definitely assigned in the constructor.: friends Person []constructor(name : string) {this.name =name }}
Example 5
ts
abstract class Person {public abstract name: string}class Student extends Person {public name: string | string[] = ["Mike North"]}
Click here for the answer
No, this will not compile.
tsTry
abstract classPerson {public abstractname : string}classStudent extendsPerson {publicProperty 'name' in type 'Student' is not assignable to the same property in base type 'Person'. Type 'string | string[]' is not assignable to type 'string'. Type 'string[]' is not assignable to type 'string'.2416Property 'name' in type 'Student' is not assignable to the same property in base type 'Person'. Type 'string | string[]' is not assignable to type 'string'. Type 'string[]' is not assignable to type 'string'.: string | string[] = ["Mike North"] name }
Example 6
ts
interface Color {red: numbergreen: numberblue: number}function printColor(color: Color) {// ... //}printColor({red: 255,green: 0,blue: 0,alpha: 0.4,})
Click here for the answer
No, this will not compile.
tsTry
interfaceColor {red : numbergreen : numberblue : number}functionprintColor (color :Color ) {// ... //}printColor ({red : 255,green : 0,blue : 0,Object literal may only specify known properties, and 'alpha' does not exist in type 'Color'.2353Object literal may only specify known properties, and 'alpha' does not exist in type 'Color'.: 0.4, alpha })
Example 7
ts
type Color = {red: numbergreen: numberblue: number}class ColorValue implements Color {constructor(public red: number,public green: number,public blue: number) {}}
Click here for the answer
Yes, this will compile.
tsTry
typeColor = {red : numbergreen : numberblue : number}classColorValue implementsColor {constructor(publicred : number,publicgreen : number,publicblue : number) {}}
Example 8
ts
export class Person {name: string = ""}interface Person {age?: number}
Click here for the answer
No, this will NOT compile. When one part of a merged declaration is exported, all other parts must be exported as well.
tsTry
export classIndividual declarations in merged declaration 'Person' must be all exported or all local.2395Individual declarations in merged declaration 'Person' must be all exported or all local.{ Person name : string = ""}interfaceIndividual declarations in merged declaration 'Person' must be all exported or all local.2395Individual declarations in merged declaration 'Person' must be all exported or all local.{ Person age ?: number}
Example 9
ts
class Person {name: stringconstructor(userId: string) {// Fetch user's name from an API endpointfetch(`/api/user-info/${userId}`).then((resp) => resp.json()).then((info) => {this.name = info.name // set the user's name})}}
Click here for the answer
No, this will NOT compile. The callback passed to .then
is not
regarded as a “definite assignment”. In fact, all callbacks are treated this way.
tsTry
classPerson {Property 'name' has no initializer and is not definitely assigned in the constructor.2564Property 'name' has no initializer and is not definitely assigned in the constructor.: string name constructor(userId : string) {// Fetch user's name from an API endpointfetch (`/api/user-info/${userId }`).then ((resp ) =>resp .json ()).then ((info ) => {this.name =info .name // set the user's name})}}
Example 10
ts
enum Language {TypeScript = "TS",JavaScript,}enum Editor {SublimeText,VSCode = "vscode",}enum Linter {ESLint,TSLint = "tslint",JSLint = 3,JSHint,}
Click here for the answer
No, this will NOT compile, but it’s probably more nuanced than you expected!
Once you provide a string initializer for an enum member, all following enum members need an explicit initializer of some sort, unless you go back to numeric enum values, at which point inference takes over again.
Ok, this one wasn’t really fair :)
tsTry
enumLanguage {TypeScript = "TS",Enum member must have initializer.1061Enum member must have initializer., JavaScript }enumEditor {SublimeText ,VSCode = "vscode",}enumLinter {ESLint ,TSLint = "tslint",JSLint = 3,JSHint ,}
Example 11
ts
function handleClick(evt: Event) {const $element = evt.target as HTMLInputElementif (this.value !== "") {this.value = this.value.toUpperCase()}}
Click here for the answer
No, this will NOT compile. When you have a free-standing function like this,
and refer to the this
value, we need to give it a type of some sort.
tsTry
functionhandleClick (evt :Event ) {const$element =evt .target asHTMLInputElement if ('this' implicitly has type 'any' because it does not have a type annotation.2683'this' implicitly has type 'any' because it does not have a type annotation.this .value !== "") {'this' implicitly has type 'any' because it does not have a type annotation.'this' implicitly has type 'any' because it does not have a type annotation.2683this .value =this .value .toUpperCase ()
2683'this' implicitly has type 'any' because it does not have a type annotation.'this' implicitly has type 'any' because it does not have a type annotation.}}
Here’s a version that would compile
tsTry
functionhandleClick (this :HTMLInputElement ,evt :Event ) {const$element =evt .target asHTMLInputElement if (this.value !== "") {this.value = this.value .toUpperCase ()}}
Example 12
ts
class Person {#name: stringprivate age: numberconstructor(name: string, age: number) {this.#name = namethis.age = age}}class Student extends Person {#name: string | string[]private age: numberconstructor(name: string, age: number | null) {super(name, age || 0)this.#name = namethis.age = age}}
Click here for the answer
No, this will NOT compile. Because TS private
fields are just “checked
for access at build time”
and are totally accessible outside the class at runtime, there’s a collision
between the two age
members.
As a result Student
is not a valid subclass of Person
tsTry
classPerson {#name: stringprivateage : numberconstructor(name : string,age : number) {this.#name =name this.age =age }}classClass 'Student' incorrectly extends base class 'Person'. Types have separate declarations of a private property 'age'.2415Class 'Student' incorrectly extends base class 'Person'. Types have separate declarations of a private property 'age'.extends Student Person {#name: string | string[]privateage : numberconstructor(name : string,age : number | null) {super(name ,age || 0)this.#name =name this.Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.2322Type 'number | null' is not assignable to type 'number'. Type 'null' is not assignable to type 'number'.age =age }}
Example 13
ts
class Person {#name: stringconstructor(name: string) {this.#name = name}}function makeName(name: string | string[]): string {if (Array.isArray(name)) return name.join(" ")else return name}class Student extends Person {#name: string | string[]constructor(name: string | string[]) {super(makeName(name))this.#name = name}}
Click here for the answer
Yes, this will compile. Because Ecma #private
fields are not visible,
even at runtime, outside of the class, there’s no collision between the
two #name
members.
tsTry
classPerson {#name: stringconstructor(name : string) {this.#name =name }}functionmakeName (name : string | string[]): string {if (Array .isArray (name )) returnname .join (" ")else returnname }classStudent extendsPerson {#name: string | string[]constructor(name : string | string[]) {super(makeName (name ))this.#name =name }}