ts-ast-viewer
: Useful tool for viewing abstract syntax tree created by TypeScript compiler
const strArray1: string[] = ['here', 'are', 'strings'];
const strArray2: Array<string> = ['more', 'strings', 'here'];
function getReview(title: string): string | number {
if (title === 'A New Hope') {
return 'An instant classic!';
}
else {
return Math.floor(Math.random() * 10);
}
}
const movieTitle: string = 'A New Hope';
const movieReview: string | number = getReview(movieTitle);
console.log(`Movie title: ${movieTitle}`);
if (typeof movieReview === 'string') {
/**
* The type hint will show that the compiler has narrowed the type of `movieReview` to be
* a `string` based on the `if` condition
*/
console.log(`Review: ${movieReview}`);
}
else {
/**
* The type hint will show that the compiler has narrowed the type of `movieReview` to be
* a `number` since that's the only logical possibility when considering the `if` condition.
*/
console.log(`Review: ${movieReview}`);
}
function simpleExample(score: number, message: string): string {
return `Score: ${score}\nAdditional feedback: ${message}`;
}
?
after parameter namefunction createCustomer(name: string, age?: number) { }
function getBookByTitle(title: string = 'The C Programming Language') { }
function getBookByTitle(title: string = getMostPopularBook()) { }
function getBooksReadForCustomer(name: string, ...bookIDs: number[]) { }
let booksForLeigh = getBooksReadForCustomer('Leigh', 2, 5);
let booksForDaniel = getBooksReadForCustomer('Daniel', 2, 5, 12, 42);
function getTitles(author: string): string[];
function getTitles(available: boolean): string[];
function getTitles(bookProperty: string | boolean): string[] {
let foundTitles: string[] = [];
if (typeof bookProperty === 'string') {
// get books by author, add to foundTitles
}
else if (typeof bookProperty === 'boolean') {
// get books by availability, add to foundTitles
}
return foundTitles;
}
type ReleaseFunc = (someYear: number) => string;
function ReleaseMessage(year: number): string {
return 'Year released: ' + year;
}
let releaseFunc: ReleaseFunc = ReleaseMessage;
let message: string = releaseFunc(2024);
NOTE: The below method of creating function types is considered deprecated.
function ReleaseMessage(year: number): string {
return 'Year released: ' + year;
}
let releaseFunc: (someYear: number) => string;
releaseFunc = ReleaseMessage;
let message: string = releaseFunc(2024);
never
⚠️ BEWARE: In a class that extends an interface, TypeScript will not throw an error if a class method's signature is subset of the method defined by the interface. However, TypeScript will throw an error if a class method's signature is a superset of the method defined by the interface.
interface Duck {
color?: string;
quack: () => void;
swim: () => void;
walk: () => void;
}
const probablyADuck = {
quack: () => console.log('quacking like a duck'),
swim: () => console.log('swiming like a duck'),
walk: () => console.log('walking like a duck'),
}
function FlyOverWater(bird: Duck) { }
FlyOverWater(probablyADuck);
function createMovieID(name: string, id: number): string {
return name + id;
}
interface IDBuilder {
(str: string, int: number): string;
}
const idBuilder: IDBuilder = createMovieID;
/* As a property in another interface */
interface Movie {
title: string;
director: string;
yearReleased: number;
streaming: boolean;
length?: number;
logReview?: ReviewLogger;
}
interface ReviewLogger {
(review: string): void;
}
interface LibraryResource {
catalogNumber: number;
}
interface Book {
title: string;
}
interface Encyclopedia extends LibraryResource, Book {
volume: number;
}
interface Librarian {
doWork: () => void;
}
class ElementarySchoolLibrarian implements Librarian {
doWork() {
console.log('Reading to and teaching children...');
}
}
class Author {
name: string;
constructor(authorName: string) {
this.name = authorName;
}
}
/* Identical functionality to above */
class Author {
constructor(public name: string) { }
}
abstract
keywordabstract class Video {
private _producer: string = '';
constructor(public title: string, protected year: number) {
console.log('Creating a new Video...');
}
get producer(): string {
return this._producer.toUpperCase();
}
set producer(newProducer: string) {
this._producer = newProducer;
}
abstract printCredits(): void;
}
class Documentary extends Video {
constructor(docTitle: string, docYear: number, public subject: string) {
super(docTitle, docYear);
}
printCredits(): void {
console.log(`Producer: ${this.producer}`);
}
}
abstract class Video {
private _producer: string = '';
constructor(public title: string, protected year: number) {
console.log('Creating a new Video...');
}
get producer(): string {
return this._producer.toUpperCase();
}
set producer(newProducer: string) {
this._producer = newProducer;
}
abstract printCredits(): void;
}
const Musical = class extends Video {
printCredits(): void {
console.log(`Musical credits: ${this.producer}`);
}
}
const myMusical = new Musical('Grease', 1978);
myMusical.producer = 'Sing-Song Pictures';
myMusical.printCredits();
/* Just to show what's possible :] */
class Course extends class { title: string = ''; } {
subject: string = '';
}
"moduleResolution"
property
"Classic" | "Node"
Classic | Node |
---|---|
Defalut when emitting "AMD" , "UMD" , "System" , or "ES2015" modules. |
Default when emitting "CommonJS" modules |
Simple - compiler traverses directories looking for right module. If relative reference, exact module location provided as part of import statement. If non-relative reference, compiler walks up directory tree looking for module starting in location of importing file | Closely mirrors Node module resolution - For relative references, compiler looks for file or directory with name specified on import statement. For non-relative references, walks up directory tree looking for folder named node_modules and will try to locate module there. |
Less configurable | More configurable |
T
(e.g. Array<T>
)Array
genericlet poetryBooks: Book[];
let fictionBooks: Array<Book>;
const historyBooks = new Array<Book>(5);
function logAndReturn<T>(thing: T): T {
console.log(`The Thing: ${thing}`);
return thing;
}
const someString: string = logAndReturn<string>('log this');
const someBool: boolean = logAndReturn<boolean>(true);
interface Inventory<T> {
getNewestItem: () => T;
addItem: (newItem: T) => void;
getAllItems: () => Array<T>;
}
let bookInventory: Inventory<Book>;
const allBooks: Array<Book> = bookInventory.getAllItems();
class Catalog<T> implements Inventory<T> {
private catalogItems = new Array<T>();
addItem(newItem: T) {
this.catalogItems.push(newItem);
}
// implement other interface methods here
}
const bookCatalog = new Catalog<Book>();
extends
keywordinterface CatalogItem {
catalogNumber: number;
}
class Catalog<T extends CatalogItem> implements Inventory<T> {
// implement interface methods here
}
.d.ts
function logMethodInfo(originalMethod: any, _context: ClassMethodDecoratorContext) {
return function replacementMethod(this: any, ...args: any[]) {
console.log(`Decorated construct: ${_context.kind}`);
console.log(`Decorated construct name: ${_context.name as string}`);
const result = originalMethod.call(this, ...args);
return result
}
}
class Documentary extends Video {
constructor(docTitle: string, docYear: number, public subject: string) {
super(docTitle, docYear);
}
@logMethodInfo
printItem(): void {
super.printItem();
console.log(`Subject: ${this.subject} (${this.year})`);
}
printCredits(): void {
console.log(`Producer: ${this.producer}`);
}
}