const values: number[] = [1, 2, 3];
const values2: Array<number> = [1, 2, 3];
values.push("a"); // TypeErrorYou cannot push a string into an array declared as an array of numbers.
const data: [string, number] = [msg, size];
data[0].substr(1);
data[1].substr(1); // TypeErrorYou cannot use a string method on a number.
let v1: undefined = undefined;
let v2: null = null;
v1 = 123; // TypeError
let v3: number | undefined = undefined;
v3 = 123;You cannot assign a number to a variable of undefined type.
undefined and null can be used with other types to declare a variable as a union type, which is used with |.
let v1: 10 | 20 | 30;
v1 = 10;
v1 = 15; // TypeError
let v2: "police" | "firefighter";
let v2 = "doctor"; // TypeErrorWhen you declare a variable with a certain value, the value becomes its literal type. v1 can be 10, 20, or 30, and v2 can be only either ‘police’ or ‘firefighter’
any type
any can be anything. it could be either a number or a string. Any type also could be a function. If you are trying to use TypeScript to change codes which have been written in JavaScript, it is helpful to use any type. But if you use it too much, it defeats the purpose of using TypeScript.
void vs never
If a function does not return anything, it could be declared void. And if a function stops due to an exception or does not stop due to an infitie loop, it can be declared never
function f1(): void {
    console.log('hello')    // this function does not return anything
}
function f2(): never {
    throw new Error('some error');   // this function stops due to an exception/error
}
function f3(): never {
    while (true) {
        ...          // this function has an infinite loop
    }
}let v: obejct;
v = {
    name: 'abc';
};
console.log(v.prop1);   // TypeErrorSince there is no information about the object property, it throws a TypeError. If you want to declare a type with information about properties included, you have to use interface, which will be explained later.
& and Union Type is declared with |let v1: (1 | 3 | 5) & (3 | 5 | 7);
v1 = 3;
v1 = 1; // TypeErrorv1 can be either 3 or 5 and nothing else.
type Width = number | string;
let width: Width;
width = 100;
width = "100px";You are assigning number | string to a type variable Width. As a variable width is declared with the type of Width, the variable can be either number or string.
enum Fruit {
  Apple,
  Banana,
  Orange,
}
const v1: Fruit = Fruit.Apple;
const v2: Fruit.Apple | Fruit.Banana = Fruit.Banana;You declare Fruit by using enum type. v1 has the type of Fruit and has been assigned with the value Fruit.Apple, and v2 has the type of Fruit.Apple. I think
enum Fruit {
  Apple,
  Banana = 5,
  Orange,
}
console.log(Fruit.Apple, Fruit.Banana, Fruit.Orange); // 0, 5, 6If you do not assign anything to an element of enum type, 0/zero is automatically assigned to it. And if you assign a number to an element, the next element gets a number which is greater than the number assigned to the previous element—unless you declare it otherwise.
When you compile an enum type variable;
var Fruit;
(function (Fruit) {
  Fruit[(Fruit["Apple"] = 0)] = "Apple";
  Fruit[(Fruit["Banana"] = 5)] = "Banana";
  Fruit[(Fruit["Orange"] = 6)] = "Orange";
})(Fruit || (Fruit = {}));
console.log(Fruit.Apple, Fruit.Banana, Fruit.Orange); // 0, 5, 6the enum type exists as an object, and each element is mapped bi-directionally with the key and value.
If you use it for run-time;
enum Fruit {
  Apple,
  Banana = 5,
  Orange,
}
console.log(Fruit.Banana); // 5
console.log(Fruit["Banana"]); // 5
console.log(Fruit[5]); // Banana     << bi-directional mappingBut if you assign a string to an element of an enum type, it is uni-directionally mapped since the same string could be assigned to different elements.
In order to declare a function, you need types of parameters and returns. You can declare types of parameters and returns using a colon(:)
function getInfoText(name: string, age: number): string {
  const nameText = name.substr(0, 10);
  const ageText = age >= 35 ? "senior" : "junior";
  return `name: ${nameText}, age: ${ageText}`;
}
const v1: string = getInfoText("mike", 23);
const v2: string = getInfoText("mile", "23"); // TypeError
const v3: number = getInfoText("mike", 23); // TypeErrorthe types of parameters are declared inside parenthesis, and the type of return is declared right before the curly brackets;
You can declare the above function like this as well;
const getInfoText: (name: string, age: number) => string = function (name, age) {
    ...
}You can declare an optional parameter using a question mark like below
function getInfoText(name: string, age: number, language?: string): string {
  const nameText = name.substr(0, 10);
  const ageText = age >= 35 ? "senior" : "junior";
  const languageTet = language ? language.substr(0, 10) : "";
  return `name: ${nameText}, age: ${ageText}, lanauge: ${languageText}`;
}
getInfoText("mike", 23, "ko");
getInfoText("mile", "23"); //
getInfoText("mike", 23, 123); // TypeErrorThe second case does not throw a TypeError since language is an optional variable. However, the third case throws a TypeError since the type of language has to be a string if it is used.
You can also assign undefined buy using union type.
function getInfoText(
    name: string,
    language: string | undefined,
    age: number,
): string {
    ...
}
getInfoText('mike', undefined, 23);This does not throw a TypeError, but its usability and readability is extremely low. You can pre-assign a value to a parameter like you would do in Python. I won’t write about that here
You can assign this type of a function as the first parameter of a function like below
function getParam(this: string, index: number): string {
  const params = this.splt(","); // TypeError
}The code above throws a TypeError since the type of this has been declared as string. If you do not declare the type of this, it would not have thrown a TypeError. And index here is the first parameter since this type is not a parameter.
You use interface when you add a method to a primitive type like below;
interface String {
  getParam(this: string, index: number): string;
}
String.prototype.getParam = getParam;
console.log("asdf, 1234, ok ".gerParam(1));You are adding getParam method to a primitive type String by using interface
Since JavaScript is a Dynamically Typed Language, one functioncan have different parameter types and return types. In TypeScript, you can use function overload to declare multiple types within a single function.
function add(x: number | string, y: number | string): number | string {
  if (typeof x === "number" && typeof y === "number") {
    return x + y;
  } else {
    const result = Number(x) + Number(y);
    return result.toString();
  }
}
const v1: number = add(1, 2); // TypeError
console.log(add(1, "2"));const v1 throws a TypeError even though both parameters and return are numbers. This is because the type of the function was not declared specifically. This is how you are supposed to declare a function using function overload
functino add(x: number, y: number): number;
function add(x: string, y: string): string;
function add(x: number | string, y: number | string): number | string {
    ...
}Basically you are declaring a function with all the possible options