number : All numbers, no differentiation between integers or floats
1, 5.3, -10
string : All text values
'Hi', "Hi", `Hi`
boolean : Just these two, no "truthy", or "falsy" values
true, false
object : Any JavaScript object, more specific types(type of object) are possible
{age: 30}
array : Any Javascript array, type can be flexible or strict(regarding the element types)
[1, 2, 3]
tuple : Added by TypeScript, Fixed-length array (Not in JavaScript)
[1, 2]
enum : Added by TypeScript, Automatically enumerated global constant identifiers
enum{NEW, OLD}
any : Any kind of value, no specific type assignment
number, string, boolean, object, etc
function add(n1: number, n2: number, showResult: boolean, phrase: string) {
if(showResult){
console.log(phrase + n1 + n2);
}
}
const num1 = 5;
const num2 = 2.8;
const printResult = true;
const resultPhrase = 'Result is:' ;
Result is: 52.8
function add(n1: number, n2: number, showResult: boolean, phrase: string) {
const result = n1 + n2;
if(showResult){
console.log(phrase + result);
}
}
const num1 = 5;
const num2 = 2.8;
const printResult = true;
const resultPhrase = 'Result is:' ;
Result is: 7.8
let num1;
num1 = 5;
let num2 = 5;
자동으로 number타입으로 변환됨
let num1: number;
num1 = '5'; //ERROR
number type에 string type을 초기화하려고 하기 때문에 Error발생
let resultPhrase = 'Result is: ';
resultPhrase = 0; //ERROR
resultPhrase는 자동으로 string type이 되었으므로 다른 type으로 초기화하려고 하기 때문에 Error발생
let num1: number = 5;
코드에는 문제가 없지만 필요하지 않은 타입 명시를 하기 때문에 좋지 않은 관행임
const person = {
name: '박상준',
age: 23
}
console.log(person.name);
typescript 컴파일러가 자동으로 생성하여 인식하는 것
const person: {
name : string;
age : number;
} = {
name: '박상준',
age: 23
}
console.log(person.name);
const product = {
id: 'abc1',
price: 12.99,
tags: ['great-offer', 'hot-and-new'],
details: {
title: 'Red Carpet',
description: 'A great carpet - almost brand-new!'
}
}
console.log(product.details.title);
중첩된 객체를 사용하는 이유는 데이터를 구조화하고 복잡성을 관리하기 위함, 코드를 조직화하고 유지보수하기 쉽게 만듦
const person = {
name: '박상준',
age: 23
hobbies: ['WorkingOut', 'Coding']
}
console.log(person.name);
let arrayExaple: string[];
arrayExample: ['WorkingOut', 1];
string type 배열로 명시하였는데 다른 타입이 들어가있어 Type Error 뜸
let arrayExaple: any[];
arrayExample: ['WorkingOut', 1];
any type을 사용하여 해결할 수 있지만 TypeScript의 이점을 사용하지 않게 되는 거임 (any type에 대해서는 추후 계속해서 설명할 예정)
const person = {
name: '박상준',
age: 23,
hobbies: ['WorkingOut', 'Coding']
}
for (const hobby of person.hobbies) {
console.log(hobby.toUpperCase());//"WORKINGOUT", "CODING"
console.log(hobby.map());//ERROR
}
map() 함수는 array type에서 접근 가능한데 string type에서 접근하고 있기 때문에 ERROR 발생
'const hobby of person.hobbies' 구문은 'person.hobbies' 배열의 각 요소를 반복하면서 그 값을 'hobby'라는 변수에 할당하는 JavaScript의 for...of 반복문입니다.
'person.hobbies' 배열에는 'WorkingOut'과 'Coding'이라는 두 개의 문자열이 들어있게 되고, for...of 반복문이 실행될 때, 'hobby'에는 각 반복에 따라 'WorkingOut' 또는 'Coding'이라는 문자열이 할당됨
JavaScript에는 없는 Fixed-length array 'Tuple'
목적 : 배열의 길이를 고정하고, 같은 type의 값이 입력될 경우에만 접근 가능하도록 한다.
const person = {
name: '박상준',
age: 23,
hobbies: ['WorkingOut', 'Coding'],
role: [2,'Dev']
}
person.role.push('admin');
person.role[1] = 10;
typescript 컴파일러가 자동으로 생성하여 인식하는 것
const person: {
name : string;
age : number;
hobbies: string[];
role: (string | number)[];
} = {
name: '박상준',
age: 23,
hobbies: ['WorkingOut', 'Coding'],
role: [2,'Dev']
}
person.role.push('admin');
person.role[1] = 10;
console.log(person.role);
2
10
"admin"
출력 결과를 보듯 목적과 달리 고정되어 있지 않고 string값이 number로 바뀌었다.
위 예제 코드는 union type으로 string or number type이면 접근이 가능, 추후 계속해서 설명할 예정
const person: {
name : string;
age : number;
hobbies: string[];
role: [number, string];
} = {
name: '박상준',
age: 23,
hobbies: ['WorkingOut', 'Coding'],
role: [2,'Dev']
}
person.role.push('admin');
person.role[1] = 10; //ERROR
person.role = [0, 'admin', 'user'];//ERROR
person.role = [0, 'admin'];
배열이 고정되었기 때문에 해당 index의 타입에 맞지 않거나 배열의 길이를 변경하려고 하고 있기 때문에 ERROR가 발생함.
tuple type 사용을 위해선 속성을 명시해줘야 함
2
"admin"
"admin"
튜플 타입에서 'push' method가 허용되는 이유는 JavaScript와의 호환성 때문에 유연성을 갖기 위해 허용됨. 튜플을 사용한다면 'push' method를 사용 안 하는 것을 권장함
관리자 모드와 같이 'Admin', 'Read only'등 과 같은 모드와 유사한 형태를 사용할 때 유용한 타입
const ADMIN = 0;
const READ_ONLY = 1;
const DEV = 2;
const person = {
name: '박상준',
age: 23,
hobbies: ['WorkingOut', 'Coding'],
role: ADMIN
}
if (person.role === ADMIN) {
consol.log("I'm admin");
}
단점 : role type이 number로 컴파일 되기 때문에 어떤 숫자든 저장될 수 있음 또, 상수를 저장하고 관리해야하므로 번거로움
enum Role { ADMIN, READ_ONLY, DEV };
const person = {
name: '박상준',
age: 23,
hobbies: ['WorkingOut', 'Coding'],
role: Role.ADMIN
}
if (person.role === ADMIN) {
consol.log("I'm admin");
}
enum의 변수명의 앞은 대문자로 하는 것이 관례
var Role;
(function (Role) {
Role[Role["ADMIN"] = 0] = "ADMIN";
Role[Role["READ_ONLY"] = 1] = "READ_ONLY";
Role[Role["DEV"] = 2] = "DEV";
})(Role || (Role = {}));
;
var person = {
name: '박상준',
age: 23,
hobbies: ['WorkingOut', 'Coding'],
role: Role.ADMIN
};
enum Role1 { ADMIN, READ_ONLY, DEV } // ADMIN = 0, READ_ONLY = 1, DEV = 2
enum Role2 { ADMIN = 5, READ_ONLY, DEV }// ADMIN = 5, READ_ONLY = 6, DEV = 7
enum Role3 { ADMIN = 'ADMIN', READ_ONLY = 100, DEV = 200 }// ADMIN = "ADMIN", READ_ONLY = 100, DEV = 200
default로 0부터 시작해서 1씩 증가하며, 숫자를 지정시 해당 숫자부터 1씩 증가함
열거형이 아니라 단일로도 사용할 수 있음
어느 타입이든 허용하지만 TypeScript의 이점을 없애버림
let some: any;
some = 1;
some = 'something';
어느 타입으로든 초기화 가능함
let something: any[];
something = 21; //ERROR
something = ['some', 1, 2];
any type 배열이기 때문에 배열안 요소가 어느 타입이든 상관 없는 거임
if (typeof n1 !== 'number' || typeof n2 !== 'number') {
throw new Error('Incorrect input!');
}
어떤 종류의 타입으로 저장될질 알 수 없는 경우 특정 값에 대해 원하는 것을 좁히기 위해 런타임 체크를 하는 경우에 주로 사용 됨
무슨 타입을 사용할지 명확히 안다면 any type을 사용 안 하는 것을 권장함
여러 타입을 허용하기 위해 사용하는 타입
function combine(input1: number | string, input2: number | string) {
const result = input1 + input2; // ERROR
}
const combineNum(30, 26);
const combineString('combine', 'String');
number type 과 string type을 받을 수 있지만 런타임 체크를 통하여 해결할 수 있음
let result;
if (typeof input1 === 'number' && typeof input2 === 'number') {
result = input1 + input2;
} else {
result = input1.toString() + input2.toStrin();
}
return result;
toString()은 number type을 string type으로 변환 시켜주는 method
특정 값을 정확하게 나타내는 타입, enum과 유사하지만 enum은 여러 개의 값 중 하나를 선택하는 데 사용되어 유연한 반면, literal은 특정 값을 나타내기 위해 사용되고 엄격한 제약을 가지고 있음
let color: 'red' | 'blue'; // 문자열 리터럴 타입
let age: 25; // 숫자 리터럴 타입
name = 'red';
name = 'yellow'; // ERROR
age = 25;
age = 30; // ERROR
union 타입으로 여러 개의 literal 선언 가능
function combine(
input1: number | string,
input2: number | string,
resultConversion: 'as-number' | 'as-text'
) {
let result;
if(typeof input1 === 'number' && typeof input2 === 'number' || resultConversion === 'as-number') {
result = +input1 + +input2;
} else {
result = input1.toString() + input2.toString();
}
return result;
}
console.log(combine(30, 26, 'as-number'));
console.log(combine('30', '26', 'as-number'));
console.log(combine('combine', 'Name', 'as-text'));
console.log(combine('Error', 'Example', 'as-tex')); //ERROR
56
56
combineName
참조
변수 앞 + 는 정수로 변환하는 자바스크립트 연산자임
let a = 'abc'; +a 한다면 NaN(Not a Number)
let input1: number | string;
let input2: number | string;
let input3: number | string;
let input4: number | string;
이와 같이 중복된 형식을 가독성 좋게 변경할 수 있음
type Combinable = number | string;
type ConversionDescriptor = 'as-number' | 'as-text';
type User = { name: string; age: number };
let input1: Combinable;
let input2: Combinable;
let input3: Combinable;
let input4: Combinable;
let resultConversion: ConversionDescriptor;
const u1: User = { name: 'Max', age: 30 };
type 형식은 TypeScript에서 사용가능하며, 'Date'와 같은 JavaScript에 내장 별칭으로는 사용이 불가함
type User = { name: string; age: number };
function greet(user: User) {
console.log('Hi, I am ' + user.name);
}
function isOlder(user: User, checkAge: number) {
return checkAge > user.age;
}
코드 가독성과 재사용성을 높여주고, 코드 작성시간을 줄여 줄 수 있음
TypeScript에서 Function의 return type에도 type을 지정할 수 있음. 만약 타입이 올바르지 않다면 ERROR를 발생시킴
function add_1(n1: number, n2: number): string { //ERROR
return n1 + n2;
}
function add_2(n1: number, n2: number): number {
return n1 + n2;
}
반환되는 값에 대한 타입을 명시해줄 수 있지만, 사용에 따라 컴파일러가 추론하게끔 하는 방법도 있음
function add(n1: number, n2: number): number {
return n1 + n2;
}
function printResult(num: number) {
console.log('Result: ' + num);
}
printResult(add(5, 12));
이때 컴파일러는
function printResult(num: number): void { }로 인식하며 함수는 void type을 반환함
function printResult(num: number): void {
console.log('Result: ' + num);
}
function printResult_1(num: number): undefined { //ERROR
console.log('Result: ' + num);
}
function printResult_2(num: number): undefined {
console.log('Result: ' + num);
return;
}
return값이 없다면 void, return값이 있지만 정의되지 않았다면 undefined
function add(n1: number, n2: number): number {
return n1 + n2;
}
let combineValues = add;
console.log(combinevalues(8, 8));
위와 같이 함수를 포인터로 사용할 수 있음, 하지만 변수를 사용하기에 다양한 값이 저장 될 수 있음
function add(n1: number, n2: number): number {
return n1 + n2;
}
let combineValues;
combineValues = add;
combineValues = 5; //Runtime ERROR
console.log(combineValues(8, 8));
컴파일에는 문제가 없었지만 런타임 에러가 뜨게 됨
function printResult(num: number): void {
console.log('Result: ' + num);
}
function add(n1: number, n2: number): number {
return n1 + n2;
}
let combineValues: Function;
combineValues = add;
combineValues = printResult;
console.log(combineValues(8, 8));
undefined
변수를 Function으로 명시해 줘서 해결해 주었지만, 여전히 다른 함수도 사용할 수 있기에 문제가 존재함
function printResult(num: number): void {
console.log('Result: ' + num);
}
function add(n1: number, n2: number): number {
return n1 + n2;
}
let combineValues: (a: number, b: number) => number;
combineValues = add;
combineValues = printResult; //ERROR
console.log(combineValues(8, 8));
매개 인수와 반환 타입을 사용하는 해당 함수에 맞게 설정하여 요구사항과 다를 시 ERROR를 도출해낼 수 있음
//함수 선언
function addAndHandle(n1: number, n2: number, cb: (num: number) => void) {
const result = n1 + n2;
cb(result);
}
//함수 호출
addAndHandle(10, 20, (result) => {
console.log(result);
return result; //Ignore
});
선언부에서
() => void로 명시해줌으로 return으로 반환을 해줘도 반환할 수 있는 어떤 결과를 무시하겠다는 뜻임
let userInput: unknown;
let userName: string;
userInput = 5;
userInput = 'Max';
userName = userInput; // ERROR
unknown이기 때문에 타입 에러가 뜨게 됨
let userInput: any;
let userName: string;
userInput = 5;
userInput = 'Max';
userName = userInput;
any 타입은 뭐든 허용 가능하기에 에러 안 뜸
let userInput: unknown;
let userName: string;
userInput = 5;
userInput = 'Max';
if (typeof userInput === 'string') {
userName = userInput;
}
위와 같이 체크를 해준다면 에러가 없음을 확인할 수 있음
function generateError (message: string, code: number) {
trow { message: message, errorCode: code };
}
generateError('An error occurred!', 500);
컴파일러가 반환값이 없으므로 아래와 같이 void로 되지만
function generateError (message: string, code: number): void {
trow { message: message, errorCode: code };
}
generateError('An error occurred!', 500);
function generateError (message: string, code: number): never {
trow { message: message, errorCode: code };
}
generateError('An error occurred!', 500);
never 타입으로 명시해줌 으로써 반환값이 절대 없음을 명시적으로 확인할 수 있게 됨
Q1. Why are "Types" useful and offer an advantage compare to vanilla JavaScript?
A)
Types allow you to use brand-new language features that run in the browser.
B)
Types allow you to detect errors early and avoid some runtime errors.
C)
Types don't offer any significant advantages but simply offer a different way of writing code.
AnswerB
Q2. Will the following code throw a compilation error?
let userName: string;
userName = 'Maximilian';
userName = false;
A)
Yes.
B)
No, because a string is assigned first.
C)
No, because "string" is a default JavaScript type.
AnswerA : That's correct - assigning a boolean to a variable which was assigned a "string" types is not allowed and will yield a compilation error.
Q3. Does this code rely on type inference?
const age: number = 29;
A)
Yes, definitely!
B)
Not really - a type is assigned explicitly as well.
AnswerB : That's correct! TypeScript would be able to infer the type (and hence you should omit ":number") but here, we actually also have an explicit type assignment.
Q4. What's the difference between JavaScript types (e.g. typeof 'Max' => 'string') and TypeScript types (e.g. const name: string = '...')?
A)
There is no differnece.
B)
JavaScript doesn't know any types.
C)
TS types are checked during compilation, JS types during runtime.
AnswerA : That's wrong - there absolutely is an important difference.
B : That's wrong - JS DOES know some types.
C : That's correct. JS has no compilation step but at runtime, you can check for certain types (e.g. in if conditions). TS on the other hand allows you to catch certain errors during development since it checks types during compilation as well.
Q5. Which of the following snippets could be simplified by using an enum type?
A)
const users = ['Max', 'Michael', 'Julie'];
B)
const userA = { name: 'Max' };
const userB = { name: 'Michael' };
C)
const ROLE_ADMIN = 0;
const ROLE_AUTHOR = 1;
AnswerA : That's wrong - this can't really be simplified with enums. You could probably use an enum somehow but it wouldn't really be useful in most scripts.
B : That's wrong - there isn't really a useful opportunity for enums here.
C : This is a great example where enums could be used!
Q6. Will the following code throw a compilation error?
type User = {name: string; age: number};
const u1: User = ['Max', 29];
A)
Yes!
B)
No, the data types (string and number) are both used.
C)
Only a runtime error will be thrown.
AnswerA : Correct! The "User" type clearly wants an object with a "name" and an "age" property. NOT an array.
B : That's wrong. The "User" type clearly wants an object with a "name" and an "age" property. NOT an array.
C : That's wrong - a compilation error will be thrown.
Q7. Will this code make it through compilation?
type Product = {title: string; price: number;};
const p1: Product = { title: 'A Book', price: 12.99, isListed: true }
A)
Yes!
B)
No, isListed is not part of the "product" type.
C)
No, a runtime error will be thrown.
AnswerA : That's wrong - this WILL yield an error.
B : That's correct!
C : That's wrong - a compilation error will be thrown.
Q8. Will this code make it through compilation?
type User = { name: string } | string;
let u1: User = {name: 'Max'};
u1 = 'Michael';
A)
Yes!
B)
No, because 'michael' is a different name than 'Max'.
C)
No, we can't switch from an object to a string once the object has been assigned.
AnswerA : This code is fine. The union type allows either an object (with a "name" property) OR a string. You can switch values how often you want.
B : That's wrong - the concrete values don't matter at all as long as the types are correct.
C : That's wrong - you can absolutely switch!