Skip to content
Search

TypeScript

lastmod 2026-04-10created 2017-02-11101 edits

TypeScript is an open-source programming language that is a superset of JavaScript. It is developed and maintained by Microsoft and supports strict syntax. Anders Hejlsberg, lead architect of C# and creator of Delphi and Turbo Pascal, is involved in its development. It can be used for both client-side and server-side development.

TypeScript is a language designed for developing large applications while using a JavaScript engine. Because it is a superset of JavaScript, programs written in JavaScript also work as TypeScript programs.

When you define the types you want and program in TypeScript, the code is compiled to JavaScript and can be run.

TypeScript is open source and can be used on any operating system, any browser, and any host.

Categories

Projects

Type Export

Validation

Generate Declaration File

--declaration, -d
Generate .d.ts files from TypeScript and JavaScript files in your project.
--declarationMap
Create sourcemaps for d.ts files.
--emitDeclarationOnly
Only output d.ts files and not JavaScript files.

NonNullAssertion

Also, the ! attached to every member variable defined with decorators is a feature called the NonNullAssertion operator.

It states that a property marked with ! is not Null/Undefined.

Declaring a Dictionary type

interface IPerson {
   firstName: string;
   lastName: string;
}
var persons: { [id: string] : IPerson; } = {};
persons["p1"] = { firstName: "F1", lastName: "L1" };

Rather than the above approach, you can use JavaScript:Map.

Override toString method

class Foo {
    private id: number = 23423;
    public toString = () : string => {
        return `Foo (id: ${this.id})`;
    }
}

Type Casting

Integer parser:

string numStr = "123";
int numNum;

bool isParsable = Int32.TryParse(numStr, out numNum);

Casting:

let whatNum: any = 42;
let reallyNum = <number>whatNum;
console.log(typeof reallyNum); // number

as syntax:

const clueless: unknown = "1";
const clueNum: number = <number>clueless;

// another format
const clueNumPreferred = clueless as number;

Disable type checking

The comment to inline in your code is as follows.

// @ts-ignore

Or modify tsconfig.json as follows:

{
  "compilerOptions": {
    ...
    "checkJs": false
    ...
  }
}

Exsits element

"key" in obj // true, regardless of the actual value

Enum name to string

enum Enum {
    A
}
let nameOfA = Enum[Enum.A]; // "A"

String enum type

export type RouterMode = 'hash' | 'history' | 'abstract'

If you want to refer to the keys of a dictionary, you can also use keyof as follows:

export interface ChartTypeRegistry {
  bar: {
    chartOptions: BarControllerChartOptions;
    datasetOptions: BarControllerDatasetOptions;
    defaultDataPoint: number;
    metaExtensions: {};
    parsedDataType: BarParsedData,
    scales: keyof CartesianScaleTypeRegistry;
  };
  line: {
    chartOptions: LineControllerChartOptions;
    datasetOptions: LineControllerDatasetOptions & FillerControllerDatasetOptions;
    defaultDataPoint: ScatterDataPoint | number | null;
    metaExtensions: {};
    parsedDataType: CartesianParsedData;
    scales: keyof CartesianScaleTypeRegistry;
  };
  // ...
}

export type ChartType = keyof ChartTypeRegistry;

Export imported interface

// export the default export of a legacy (`export =`) module
export import MessageBase = require('./message-base');

// export the default export of a modern (`export default`) module
export { default as MessageBase } from './message-base';

// when '--isolatedModules' flag is provided it requires using 'export type'.
export type { default as MessageBase } from './message-base';

// export an interface from a legacy module
import Types = require('./message-types');
export type IMessage = Types.IMessage;

// export an interface from a modern module
export { IMessage } from './message-types';

Export the entire contents of a specific file. Useful for files like index.ts.

export * from "./StringValidator";

Accessing sub-objects through a single representative Export object (how to drop * as)

If you want to Export so that it can be imported as import MyLib from 'my-lib';, without * as, instead of import * as MyLib from 'my-lib';:

import Button from './Button.tsx';
export {type ButtonProps} from './Button.tsx';

export {Button};

export const YourUi = {
  Button,
};
export default YourUi;

extends vs implements

The differences are as follows:

  • The extends keyword is used in a class declaration or class expression to create the class you want as a subclass of another class.
  • The implements keyword is used to check whether a class satisfies an interface.

Mixin

See TypeScript:Mixins.

Declaration files

Declaration files. They are *.d.ts files.

// token-service.d.ts

import Vue from 'vue'
import TokenService from '../path/to/token-service'

declare module 'vue/types/vue' {
  interface Vue {
    $tokenService: TokenService
  }
}

Used as follows in the answer project:

import Vue from 'vue'
import { REST_API } from "./services/api";

declare module 'vue/types/vue' {
  interface Vue {
    $api: REST_API;
  }
}

Current class and method name?

Pass the class prototype (class.prototype) as an argument to the Object.getOwnPropertyNames function.

class Foo {
    bar() {
        console.log(Object.getOwnPropertyNames(Foo.prototype)); // ["constructor", "bar"]
    }
}
new Foo().bar();

Bad TypeScript habits to break now

  • 10 bad TypeScript habits to break this year
    1. Not using strict mode
    2. Defining default values with ||
      • Use ??, or define fallbacks per parameter
    3. Using any as a type
      • Replace it with unknown
    4. val as SomeType
      • Check with a type guard function
    5. Using as any in tests
    6. Optional properties
    7. Single-letter Generics
      • Use full type names that explain themselves by name alone
    8. Non-boolean boolean checks
    9. The !! operator
    10. != null

TypeScript support

In most cases, the type declaration package name should always be the same as the package name on npm, but prefixed with @types/. If needed, though, visit https://aka.ms/types to find the package for your favorite library.

Things to check when types conflict

The resolutions property in the package.json file:

  "resolutions": {
    "@types/react": "18.2.0",
    "@types/react-dom": "18.2.0"
  },

Compiler options in tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "react": ["./node_modules/@types/react"]
    },
    "types": ["jest", "react", "react-dom"],
  }
}

Troubleshooting

Could not find a declaration file for module 'xxxxx'

Method 1 - To avoid the issue I just replace it by the standard require()

:

const vue-xxxxxx = require('vue-xxxxxx');
// import { vue-xxxxxx } from 'vue-xxxxxx'
Method 2 - To avoid the issue I just replace these line in the tsconfig.json

:

{
  compilerOptions: {
    "noImplicitAny": false,
    "allowJs": true,
  }
}

TS2307: Cannot find module '@/xxxx' or its corresponding type declarations

When the following error is printed by an IDE (e.g. webstorm) or by tsc,

TS2307: Cannot find module '@/crypto' or its corresponding type declarations.

Run yarn tsc yourself and check for errors. Common problems are as follows.

  • Set compilerOptions.moduleResolution in tsconfig.json to node.
  • Add the paths to substitute to compilerOptions.paths in tsconfig.json. If they usually look like '@/source', add "@/*": ["src/*"].
  • If the entries added to compilerOptions.paths above are not relative paths (e.g. "@/*": ["src/*"]), add compilerOptions.baseUrl. It is usually "baseUrl": ".".
  • Add included and excluded paths to include and exclude in tsconfig.json. Like this:

{

"include": ["src/**/*.ts", "src/**/*.tsx", "tests/**/*.ts", "tests/**/*.tsx"],
"exclude": ["node_modules", "dist"]

}

</syntaxhighlight>

Additionally: if files meant for type declarations, such as *.d.ts files, are the problem, setting compilerOptions.skipLibCheck to true fixes it.

For images such as SVG

To use non-code assets with TypeScript, we need to defer the type for these imports. This requires a custom.d.ts file which signifies custom definitions for TypeScript in our project.

When you don't care much about the file type itself, as in many pure TypeScript Libraries

declare module "*.png";
declare module "*.jpg";
declare module "*.jpeg";
declare module "*.svg";
declare module "*.gif";

Default Export of a single SVG file:

declare module '*.svg' {
  const content: any;
  export default content;
}

Here we declare a new module for SVGs by specifying any import that ends in .svg and defining the module's content as any. We could be more explicit about it being a URL by defining the type as string. The same concept applies to other assets including CSS, SCSS, JSON and more.

If you use React:

declare module '*.svg' {
  const value: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
  export default value;
}

TypeScript: Property 'xxx' does not exist on type 'MyComponent'

How to use properties added elsewhere when using a library such as vue-class-component:

:

class MyComponent
{
    private xxx!: number;
}

Add the member variable with !. See #NonNullAssertion.

Cannot import exported interface - export not found

Given an interface like the following,

export interface B {
    b: number;
}

you can import it as follows:

import { B } from './test.model';

In this case, an export not found warning may be printed. It can be fixed as follows.

import type { B } from './test.model';

When this is undefined

If you pass a callback method that uses this from the constructor, as below, this becomes undefined inside that callback.

export default class ApiV2 {
    constructor() {
        this.api = AxiosLib.create();
        this.api.interceptors.response.use(
            this.onResponseFulfilled,
            this.onResponseRejected,
        );
    }
    async onResponseRejected(error) {
        const self = this; // self is 'undefined'
    }
}

To fix this, you can call the method through an Anonymouse Lambda in the constructor.

export default class ApiV2 {
    constructor() {
        this.api = AxiosLib.create();
        this.api.interceptors.response.use(
            (response) => {
                return response;
            },
            async (error) => {
                return this.onResponseRejected(error);
            },
        );
    }
    onResponseRejected(error) {
        const self = this; // ok !!
    }
}

Just a guess, but maybe the lambda expression captures this?

catch block error message

Use compiler option '--downlevelIteration' to allow iterating of iterators

Type 'Set<any>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.

Entry module "..." is using named and default exports together.

Entry module "src/tailwind/index.ts" is using named and default exports together. Consumers of your bundle will have to use `your-tailwind.default` to access the default export, which may not be what you want. Use `output.exports: "named"` to disable this warning.

Named Exports (export const Name = ...;) and a default Export (export default ...) are used together in the entry point module. Consolidate them into export default ....

See also

Favorite site

Webpack

Tutorials

Guide

Article

author Zer0 sitemap