let age:number = 30;
let isAdult:boolean = true;
let a:number[] = [1, 2, 3];
let a2:array<number> = [1, 2, 3];
let week1:string[] = ['mon', 'true', 'wed'];
let week2:Array<string> = ['mon', 'tue', 'wed'];
인텍스별로 타입이 다를 때 사용
let b:[string, number];
b = ['z', 1]; // 가능
b = [1, 'z']; // 불가능
b = b[0].toLowerCase(); // 가능
b = b[1].toLowerCase(); // 불가능
void
void는 함수에서 아무것도 반환하지 않을때 사용function sayHello():void{ console.log('hello'); }
never
never은 항상 에러를 반환하거나, 영원히 끝나지 않는 함수의 타입으로 사용function showError():never{ throw new Error(); } function infLoop():never{ while (true) { // do something.. } }
비슷한 값끼리 묶어져 있는 형태
enum Os {
Window,
Ios,
Android
}
let myOs:Os;
myOs = Os.Window
특정값만 입력할 수 있게 강조하고 싶을때, 그 값들이 공통점이 있을 때 사용
let a:null = null;
let b:undefined = undifined;
let user:object;
user = {
name : 'xx',
age : 30
}
console.log(user.name) // 에러 발생
// 오브젝트에는 특정 속성 값에 대한 정보가 없기 때문에 에러 발생
프로퍼티를 정해서 객체를 표현 하고자 할 때는 인터페이스를 사용한다
interface User {
name : string;
age : number;
gender? : string; // `?` 옵션처리(있어도 돼고 없어도 돼고)
}
let user : User = {
name : 'xx',
age : 30
}
user.age = 10;
user.gender = 'male'
console.log(user.age)
값에 접근은 할 수 있지만 수정은 불가능 하다
interface User {
name : string;
age : number;
gender? : string;
readonly birthYear : number;
}
let user : User = {
name : 'xx',
age : 30,
birthYear : 2000, // 읽기전용에서 최초생성할때만 할당이 가능하고 이후에는 수정안됨
}
user.age = 10;
user.gender = 'male'
user.birthYear = 1990; // 읽기전용으로 에러 발생
interface User {
1? : string;
2? : string;
3? : string;
4? : string;
}
interface User {
[grade:nmber] : string
// grade는 어떤 단어가 와도 상관없다 key 등 상관없다
}
type Score = 'A' | 'B' | 'C' | 'F';
interface User {
[grade:nmber] : Score
// 위와 같이 먼저 선언안 Score에 할당된 값 이외에는 사용 불가능
}
interface Add { (인자값):리턴값 }
interface Add {
(num1:number, num2:number):number;
}
const add : Add = function(x, y){
return x + y
}
add(10, 20)
inferface IsAdult {
(age:number):boolean;
}
const a:IsAdult = (age) => {
return age > 19;
}
a(33) // true;
interface Car {
color: string;
wheels: number;
start(): void;
}
class Bmw implements Car {
color = 'red';
wheels = 4;
start(){
console.log('go')
}
}
interface Car {
color: string;
wheels: number;
start(): void;
}
class Bmw implements Car {
color
wheels = 4;
constructor(c:string){
this.color = c;
}
start(){
console.log('go')
}
}
const b = new Bmw('green');
console.log(b)
b.start();
interface Car {
color: string;
wheels: number;
start(): void;
}
// extends 사용으로 기존에 가지고 있는 속성을 그대로 받게 된다
interface Benz extends Car {
door: number;
stop(): void;
// 추가 할 수 있다
}
const benz : Benz = {
door : 5,
stop(){
console.log('stop');
},
// 기존에 설정되었던 값도 같이 써줘야 에러가 안남
color : white,
wheels: 4,
start(){
console.log('go')
}
}
interface Car {
color: string;
wheels: number;
start():void;
}
interface Toy {
name:string;
}
interface ToyCar extends Car, Toy {
price : number;
}
각 매개변수의 타입을 입력, 괄호뒤에는 함수가 반환하는 타입을 입력
function add(num1: number, num2: number): number {
return num1 + num2;
}
function add(num1: number, num2: number): void {
// 아무것도 리턴하지 않으면 void 입력
console.log(num1 + num2)
}
function isAdult(age: number): boolean {
return age > 19;
}
function hello(name?: string) {
return `Hello, ${name || "world"}`
}
const result = hello();
// 매개변수에 옵션(?)을 지정 안해주면 에러 발생 (매개변수를 안넣어 줘서)
default 값 설정
function hello(name = 'world') { return `Hello, ${name}`; }
function hello(name: string, age?: number): string {
if (age !== undefined) {
return `Hello, ${name}. You are ${age}.`;
} else {
return `Hello, ${name}`;
}
}
console.log(hello('same'));
console.log(hello('same', 30));
// 만약 하기와 같이
function hello(age?: number, name: string): string
선택적 매개변수가 앞으로 오면 에러를 발생 시킨다
function hello(age?: number | undefined, name: string): string {
if (age !== undefined) {
return `Hello, ${name}. You are ${age}.`;
} else {
return `Hello, ${name}`;
}
}
console.log(hello('same'));
console.log(hello(undefined, 'same'));
// 에러
function add(...nums) {
return nums.reduce((result, num) => result + num, 0);
}
add(1, 2, 3);
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
레스트 파라미터는 전달 받은 매개변수를 배열로 나타낼 수 있게 한다
즉,
function add(...nums: number[]) {
return nums.reduce((result, num) => result + num, 0);
}
add(1, 2, 3);
add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
interface User {
name: string;
}
const Sam: User = {name:'Sam'}
function showName(){
console.log(this.name) // 에러
}
const a = showName.bind(Sam);
a(); // 'Sam'
bind를 이용해서 this를 Sam 객체로 강제하고 있다
interface User {
name: string;
}
const Sam: User = {name:'Sam'}
function showName(this:User){ // this type 지정
console.log(this.name)
}
interface User {
name: string;
}
const Sam: User = {name:'Sam'}
function showName(this:User, age:number, gender: 'm' | 'f'){ // this type 지정
console.log(this.name, age, gender)
}
const a = showName.bind(Sam);
a(30, 'm');
interface User {
name: string;
age: number;
}
// age가 숫자면 User, string 이면 "나이는 숫자로 입력해주세요." 반환
function join(name: string, age: number | string): User | string {
if (typeof age === "number") {
return {
name,
age,
};
} else {
return "나이는 숫자로 입력해주세요."
}
}
const sam: User = join("Sam", 30); // 에러
const jane: string = join("Jaene", "30"); // 에러
sam이나 jane은 user객체를 반환하는데 확신이 없는 거다, 두가지다 반환할 수도 있다고 생각하고있다
함수 오버로드는 전달받은 매개변수의 갯수나 타입에 따라 다른 동작을 하게 하는 것을 의미
interface User {
name: string;
age: number;
}
// 함수 오버로드
function join(name: string, age: string): string
function join(name: string, age: number): User;
function join(name: string, age: number | string): User | string {
if (typeof age === "number") {
return {
name,
age,
};
} else {
return "나이는 숫자로 입력해주세요."
}
}
const sam: User = join("Sam", 30);
const jane: string = join("Jaene", "30");
동일한 함수지만 변수의 타입이나 갯수에 따라 다른방식으로 동작해야 된다면,
오버로드를 사용한다
const user1 = "Bob"; // user1: "Bob"
let user2 = "Tom"; // user2: string
const user1 = "Bob"; // user1: "Bob"
let user2: string | number = "Tom"; // user2: string or number
user2 = 3; // 가능
정해진 string 값을 가진 것을 문자열 리터럴 타입이라고 한다
type Job = "police" | "developer" | "teacher"
interface User {
name: string;
job: job;
}
const user: User = {
name: "Bob",
job: "developer" // job은 위에 선언된 것만 사용가능하다
}
숫자형 interface
interface HighSchoolStudent { name: string; grade: 1 | 2 | 3; }
|
은 유니온 타입이라고 하는데, 두가지 이상 타입을 지정할 때 사용한다
interface Car {
name: "car";
color: string;
start(): void;
}
interface Mobile {
name: "mobile"
color: string;
call(): void;
}
function getGift(gift: Car | Moblie) {
console.log(gift.color);
gift.start(); // 에러 // Car에만 start 함수가 있기 때문에 에러가 발생
}
function getGift(gift: Car | Moblie) {
console.log(gift.color);
// 동일한 이름의 속성을 정의하고 그것의 타입을 다르게 주므로서 두개의 인터페이스를 구분할 수 있다
// car type, mobile type
if (gift.name === "car") {
gift.start();
} else {
gift.call();
}
동일한 속성의 타입을 다르게해서 구분할 수 있는 것을 식별가능한 유니온 타입이라고 한다
교차타입은 여러타입을 합쳐서 사용한다
유니온은 or 면 교차타입은 and를 의미한다
interface Car {
name: string;
start(): void;
}
interface Toy {
name: string;
color: string;
price: number;
}
// &(엔퍼센트 기호를 사용)
const toyCar: Toy & Car = {
name: "타요",
start(){},
color: "blue",
price: 1000,
}
&
엔퍼센트 기호를 사용하고 만들어진 것에 모든 타입을 작성해줘야 한다
class Car {
constructor(color) {
this.color = color; // 에러 발생 // color 프로펄티가 Car에 없다고 나옴
}
start() {
console.log("start")
}
}
const bmw = new Car("red");
타입스크립트에서 클래스 작성할때 멤버 변수는 미리 선언을 해줘야 한다
class Car {
color: string; // 변수 미리 선언
constructor(color: string) { // 매개변수 타입도 설정
this.color = color; // 에러 발생 // color 프로펄티가 Car에 없다고 나옴
}
start() {
console.log("start")
}
}
const bmw = new Car("red");
멤버변수를 미리선언하지 않아도 되는 방법도 있다
접근제한자나 readonly 키워드를 사용하는 방법이 있다
public / readonly
class Car {
constructor(public color: string) { // 매개변수 타입도 설정
this.color = color; // 에러 발생 // color 프로펄티가 Car에 없다고 나옴
}
start() {
console.log("start")
}
}
const bmw = new Car("red");
class Car {
constructor(readonly color: string) { // 매개변수 타입도 설정
this.color = color; // 에러 발생 // color 프로펄티가 Car에 없다고 나옴
}
start() {
console.log("start")
}
}
const bmw = new Car("red");
es6 클래스는 다른 객체지향 언어들 처럼 접근 제한자를 지원하지 않는다
하지만 타입스크립트에서는 지원한다
자식 클래스나 클래스 인스턴스에서 접근이 가능하다
아무것도 표기하지 않고 작성하면 모두 public 이다
class Car {
name: string = "car"; // 앞에 아무것도 없지만 public이 있는 것과 같다
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log("start")
}
}
// Car class를 상속받은 Bmw
class Bmw extends Car {
constructor(color: string) {
super(color); // super가 없으면 에러 발생 // Car에 있는 color, name을 받아 옴
}
showName() {
console.log(super.name)
}
}
const z4 = new Bmw("black")
class Car {
private name: string = "car";
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log("start")
}
}
// Car class를 상속받은 Bmw
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name) // 에러 발생 // 자식클래스 내부에서 사용할 수 없게 된것
// name은 Car 클래스 내부에서만 사용가능 하다
}
}
const z4 = new Bmw("black")
#
사용class Car {
#name: string = "car"; // #사용으로 private 사용가능
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log("start")
console.log(this.#name) // 사용하는 쪽도 #을 써줘야 한다
}
}
class Car {
protected name: string = "car";
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log("start")
}
}
// Car class를 상속받은 Bmw
class Bmw extends Car {
constructor(color: string) {
super(color);
}
showName() {
console.log(super.name) // 에러 발생 // 자식클래스 내부에서 사용할 수 없게 된것
// name은 Car 클래스 내부에서만 사용가능 하다
}
}
const z4 = new Bmw("black")
protected도 자식 클래스에서 접근이 가능하다,
클래스 인스턴스로는 존재할 수 없다
public은 자식 클래스나 클래스 인스턴스모두 접근 할 수 있다, 아무것도 안적으면 public 이다
protected는 자식 클래스 내부에서만 접근할 수 있다
private는 가장 제한적이며, 해당 클래스 내부에서만 접근할 수 있다
#
변수명으로 적을 수 있다
static을 써주면 정적 멤버변수를 만들 수 있다
이렇게 되면 class.으로 접근이 가능하다
this가 아닌 class 이름으로 접근한다
class Car {
protected name: string = "car";
color: string;
static wheels = 4;
constructor(color: string) {
this.color = color;
}
start() {
console.log("start")
console.log(Car.wheels) // static을 사용하면 this가 아닌 class 이름을 사용한다
}
}
consele.log(car.wheels) // static을 사용하면 this가 아닌 class 이름을 사용한다
추상클래스는 클래스 앞에 abstract 키워드를 사용해서 만들 수 있다
class Car {
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log("start")
}
}
const car = new Car("red"); // 에러발생 // new키워드로 객체를 만들 수 없다
// 하기와 같이 상속을 통해서만 사용이 가능하다
class Bmw extends Car {
constructor(color: string) {
super(color)
}
}
const z4 = new Bmw("black")
추상메소드는 반드시 상속받은 쪽에서 구체적인 구현을 해줘야 한다
class Car {
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log("start")
}
abstract doSomething():void;
}
class Bmw extends Car { // 에러 발생 // 구체적인 구현 필요
constructor(color: string) {
super(color)
}
}
const z4 = new Bmw("black")
추상화는 프로퍼티나 메서드의 이름만 선언해주고,
구체적인 기능은 상속받는 쪽에서 구현해주는 것을 의미한다
추상 클래스를 상속받아 수많은 객체들이 동일하게 이 메서드를 가지고 있겠지만,
구체적인 기능은 가지각색일 수 있다
class Car {
color: string;
constructor(color: string) {
this.color = color;
}
start() {
console.log("start")
}
abstract doSomething():void;
}
class Bmw extends Car { // 에러 발생 // 구체적인 구현 필요
constructor(color: string) {
super(color)
}
doSomething(){
alert(3);
}
}
const z4 = new Bmw("black")
제네릭을 이용하면 클래스나 함수 인터페이스를 다양한 타입으로 재사용 할 수 있다
선언할때는 타입 파라미터만 적어주고 생성는 시점에 사용하는 타입을 결정한다
function getSize(arr: number[]):number {
return arr.length;
}
const arr1 = [1, 2, 3];
getSize(arr1); // 3
arr1 이 number 타입만 사용하면 상관없는데, 만약 string, boolean 등 값들이 많아지면
function getSize(arr: number[], string[]):number
이렇게 계속 추가해줘야 한다
function getSize<T>(arr):number {
return arr.length;
}
const arr1 = [1, 2, 3];
getSize(arr1); // 3
const arr2 = ["a", "b", "c"];
getSize(arr2);
const arr3 = [false, true, true];
getSize(arr3);
const arr4 = [{}, {}, { name: "Tim" }];
getSize(arr4);