.
.
.
타입 애너테이션 type annotation : 변수나 상수 혹은 함수의 인자와 반환 값에 타입을 명시적으로 선언 -> 어떤 타입 값이 저장될 것인지를 컴파일러에직접 알려주는 문법 ( 언어마다 타입 명시 방법 다름 )
비교 >
자바 : 변수에 데이터 타입을 명시 x -> 식별자를 찾지 못했다고 에러남.
항상 변수 이름보다 데이터 타입을 우선 명시해줘야 함.
test = "test";
// error : cannot find symbol test
타입스크립트 : 변수 이름 뒤에 : type 구문 붙여 <- 데이터 타입 명시
type선언부를 제거해줘도 코드가 정상적으로 작동하긴 함. 타입 추론 과정이 어려워질 뿐.
let isDone : boolean = false;
타입 사용 프로그래밍 언어 <- 값이나 객체는 하나의 구체적인 타입을 가지고 있음.
타입시스템 : 타입은 이름으로 구분되며 컴파일러 이후에도 남아있음. 이것을 명몽적으로 구체화한 것.
명확한 상속관계나 공통 인터페이스x 경우 : 타입 호환 x
interface Developer {
faceValue : number;
}
interface BankNote {
faceValue : number;
}
let developer : Developer = { faceValue : 52 };
let bankNote : BankNote = { faceValue : 1000 };
developer = bankNote; // ok
bankNote = developer; // ok
타입스크립트 : 구조로 타입을 구분( = 구조적 타이핑 )
타입스크립의 타입 = 값의 집합
so... 특정 값이 string 또는 number 타입 동시에 가질 수 있음.
type stringOrNumber = string | number;
이처럼 집합으로 나타낼 수 있는 타입스크립트의 타입 시스템을 지탱하고 있는 개념이 "구조적 서브타이핑"
구조적 서브타이핑 : 객체가 가지고 있는 속성(프로퍼티) 바탕으로 타입을 구분하는 것, 이름이 다른 객체라도 속성이 동일하면 서로 호환 가능
interface Pet {
name : string
}
interface Cat {
name : string
age : number
}
let pet : Pet;
let cat : Cat = { name : "Zag", age : 2}
pet = cat
: Cat은 Pet과 다른 타입으로 선언... but Pet이 갖고 있는 name이라는 속성 가짐.
so... Cat 타입으로 선언한 cat을 Pet 타입으로 선언한 pet에 할당가능.
구조적 서브 타이핑 -> 함수의 매개변수에도 적용 가능
interface Pet {
name : string
}
let cat = { name : "Zag", age : 2}
function greet (pet: Pet) {
console.log("Hello," + pet.name)
}
: greet( ) 함수의 매개변수에 들어갈 수 있는 값은 Pet 타입으로 제한.
...but 타입 명시 x Cat객체를 전달해도 정상 작동 o
왜냐면 : cat 객체는 Pet 인터페이스가 가지고 있는 name 속성을 가지고 있어 pet.name 속성에 접근 가능해서
so... 타입의 상속 역시 구조적 타이핑 기반 o
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class Developer {
name: string;
age: number;
sleepTime: number;
constructor(name: string, age: number, sleepTime: number) {
this.name = name;
this.age = age;
this.sleepTime = sleepTime;
}
}
function greet(p: Person) {
console.log(`Hello, I'm ${p.name}`);
}
const developer = new Developer("zig", 20, 7);
greet(developer); // Hello, I'm zig
: Developer 클래스가 Person 클래스를 상속받지 않았는데도 greet(developer)는 정상작동
왜냐 : Developer는 Person이 갖고있는 속성을 가지고 있기 때문
타입스크립트의 타입 시스템 = 구조적 서브타이핑
<-> 명목적 타이핑( ex. C++, 자바 ) : 같은 이름의 데이터 타입으로 선언된 경우에만 서로 호환됨.
class Cat {
String name;
public void hit () {}
}
class Arrow{
String name;
public void hit () {}
}
public class Main {
public static void main (String[] args) {
// error: incompatible types: Cat cannot be converted to Arrow
Arrow cat = new Cat();
// error: incompatible types: Arrow cannot be converted to Cat
Cat arrow = new Arrow();
}
}
: Cat과 Arrow 클래스는 String 타입의 name 변수와 hit() 메서드를 가지고 있다는 점에서 구조적으로 동일, 각 클래스로 생성한 인스턴스는 서로 호환 x
so... 구조가 같더라도 이름이 다르다면 다른 타입으로 취급
왜냐면? 명목적 타이핑을 채택한 언어에서는 이름으로 타입을 구분해서.
명목적 타이핑 : 타입의 동일성 equivalence을 확인하는 과정에서 구조적 타이핑에 비해 조금 더 안전함.
so... 객체의 속성을 다른 객체의 속성과 호환되지 않도록 안전성 추구함.
그런데도 타입스크립트가 구조적 타이핑을 채택한 이유? 타입스크립트가 자바스크립트를 모델링 -> 자바스크립트는 본질적으로 덕 타이핑 기반
덕타이핑 : 어떤 함수의 매개변숫값이 올바르게 주어진다면 그 값이 어떻게 만들어졌는지 신경쓰지 않고 사용한다는 개념, 어떤 타입에 부합하는 변수와 메서드를 가질 경우 해당 타입에 속하는 것으로 간주.
타입스크립트는
: 이런 동작을 그대로 모델링, 자바스크립트의 특징을 그대로 받아들여 명시적인 이름을 가지고 타입을 구분하는 대신 객체나 함수가 가진 구조적 특징을 기반을 타이핑하는 방식을 채택 (쉬운 사용성, 안정성, 객체 간 속성이 동일하다면 서로 호환)
: 객체가 가진 속성을 기반으로 타입을 검사
타입을 검사하는 시점에 따라_
interface Cube {
width: number;
height: number;
depth: number;
}
function addLines(c: Cube) {
let total = 0;
for (const axis of Object.keys(c)) {
// Element implicitly has an 'any' type
// because expression of type 'string'
// can't be used to index type 'Cube'.
// No index signature with a parameter of type 'string' was found on type 'Cube'.
const length = c[axis];
total += length;
}
}
: addLines () 함수의 매개변수인 c는 Cube 타입으로 선언, Cube 인터페이스의 모든 필드는 number 타입 -> c[axis]는 당연히 number 타입이라 예측
...but c에 들어올 객체 : 어떤 속성이든 가질 수 있음.
so... c[axis]의 타입이 string일 수도 있어 에러 발생
const namedCube {
width: 6,
height: 5,
depth: 4,
name: "test" // string 타입의 추가 속성이 정의
};
addLines(namedCube); // ok
: 타입스크립트-> c[axis]가 어떤 속성인지 알 수 x number라고 확정 x => error 발생 ( Cube타입 값이 들어갈 곳에 name 같은 추가 속성을 가진 객체도 할당할 수 있기 때문에 발생 )
이러한 한계 극복 : 유니온 (: 타입스크립트에 명목적 타이핑 언어의 특징을 가미, 식별)
점진적 타입 검사 : 컴파일 타임에 타입을 검사하면 필요에 따라 타입 선언 생략을 허용
타입 선언이 생략 -> 동적 검사 수행 : 암시적 타입 변환이 일어남.
function add(x,y){
return x+y;
}
// 위 코드는 아래와 같이 암시적 타입 변환이 일어난다.
function add(x: any, y:any):any;
add()함수의 매개변수 x와 y에 타입 선언 x
...but 타입스크립트 컴파일러 : 모두 any 타입으로 추론
필요에 따라 타입 생략 o, 타입을 점진적으로 추가할 수도 o
-> 반드시 모든 타입을 알고 있어야 x
( 알고 있을 때 최상의 결과 o )
타입 지정 x 자바스크립트 코드 -(마이그레이션)-> 타입스크립트
: 타입스크립트의 점진적 타이핑이라는 특징 유용하게 활용 o
타입스크립트의 타입 시스템은 정적 타입의 정확성 100% 보장 x
any 타입 : 타입스크립트 내 모든 타입의 종류 포함 가장 상위 타입, 어떤 타입 값이든 할당 가능.
... but, noImplicityAny 값 = true 일 때 에러 발생
왜냐면? noImplicityAny는 타입 애너테이션이 없을 때 변수가 any 타입으로 추론되는 것을 허락 x
타입스크립트 코드 작성시, 정확한 타이핑을 위해 tsconfig의 noImplicityAny 값 = true 로 설정하는 게 좋음.
타입스크립트 = 기존 자바스크립트 + 정적인 타이핑 추가
(TS = JS모든 문법 포함 / 선택적으로 타이핑 도입 -> 진입장벽 낮음.)
모든 JS = TS
모든 TS != JS
function greet(name:string){
console.log("Hello",name);
}
: 타입스크립트에서는 유효 o / 자바스크립트에서는 오류
let developer = 'Colin';
console.log(developer.toUppercase());
: 이경우, 에러 메세지 차이_
타입스크립트 : // Did you mean 'toUpperCase'?
-> 타입을 추론해서 메서드 대체를 제안
자바스크립트 : // developer .toIppercase is not a function
-> 그냥 이렇게 에러를 던져줌.
값 value : 프로그램이 처리하기 위해 메모리에 저장하는 모든 데이터 = 프로그램에서 조작하고 다룰 수 있는 어떤 표현 (다양한 형태의 데이터를 포함)
11; // 숫자 값
"hello typescript"; // 문자열 값
let foo = "bar"// 변숫값
: 객체 역시 값이다. 자바스크립트에서는 함수도 값이다. 모든 것이 객체인 언어답게 자바스크립트 함수는 런타임에 객체로 변환됨.
//함수
function goWork(developer){
console.log(`tired ${developer}`)
}
: 값은 어떠한 식을 연산한 것으로 변수에 할당 = developer라는 변수에 "zig"라는 문자열 값을 할당.
type Person = {
name : string;
age : number;
};
interface Person {
name : string;
age : number;
}
: type이나 interface 키워드로 커스텀 타입을 정의
값 공간과 타입 공간의 이름은 서로 충돌 x
-> 같은 이름 정의 가능 o
-> type 선언 내용 <- 자바스크립트 런타임에서 제거
type Developer = { isWorking : true };
const Developer = { isTyping : true }; //ok
type Cat = { name : string; age : number; };
const Cat = { slide : true };
: 타입은 주로 타입선언(:) 또는 단언문(as)으로 작성
값은 할당연산자인 =으로 작성
interface Developer {
name : string;
isWorking : boolean;
}
const developer : Developer = { name : "Zig", isWorking : true };
: 변수 developer의 타입 : Developer이며,
developer 할당값 : { name : "Zig", isWorking : true }
function test(author:Developer, date:Date): Response {
//...
}
: author의 값으로 Developer 타입이 사용
function email(options:{person:Person; subject:string;}){
//..
}
: 자바스크립트의 구조분해할당 사용 -> email 함수의 매개변수로 넘기는 options 객체를
function email({person, subject, body}){
//..
}
이렇게 풀어 쓸 수 있다.
.. but, 타입스크립크트를 구조 분해 할당하면 오류가 발생함.
function email({person:
Person, // subject;
string, // body;
string,
//..
}
: 값의 관점에서 Person가 string이 해석되어서 오류가 남.
개발자 의도 : person:Person
코드해석 : Person이 값공간에 있는걸로 해석
구조분해할당 : 자바스크립트 또는 타입스크립트에서 배열이나 객체의 속성을 개별 변수로 분해하여 그 값을 변수에 할당하는 것
class Rectangle {
constructor (height, width) {
this.height = height;
this.width = width;
}
}
const rect1 = new Rectangle(5, 4);
class Developer {
name: string;
domain: string;
constructor(name: string, domain: string) {
this.name = name;
this.domain = domain;
}
}
const me: Developer = new Developer ("zig", "frontend");
: 변수명 me 뒤에 등장하는 : Developer에서 Developer는 타입에 해당, new 키워드 뒤의 Developer는 클래스의 생성자 함수인 값으로 동작.
타입스크립트에서 클래스는 타입 애너테이션으로 사용
런타입에서 객체로 변환 -> 자바스크립트의 값으로 사용되는 특징.
enum Direcion{
Up, // 0
Down, //1
}
: 클래스처럼 타입 공간에서 타입을 제한하는 역할 ... but 자바스크립트 런타임에서 실제 값으로도 사용 가능
enum WeekDays {
MON = "Mon"
TUES = "Tues",
WEDNES = "Wednes",
THURS = "Thurs",
FRI = "Fri",
}
// 'MON' " "TUES' I "WEDNES' I "THURS' I FRI
type WeekDaysKey = keyof typeof WeekDays;
function printDay(key: WeekDaysKey, message: string) {
const day = WeekDays [key];
if (day < WeekDays.WEDNES) {
console.log(`It's still ${day)day, $(message}`);
}
}
printDay ("TUES", "wanna go home");
: enum이 타입으로 사용됨.
WeekDays enum에 keyof typeof 연산자룔 사용 -> type WeekDaysKey만들어 printDay() 함수의 key 인자에 넘겨줄 수 있는 값의 타입을 제한
이와 달리,
enum Mycolors {
BLUE = "#0000FF",
YELLOW = "#FFF00",
}
function whatBlueColor(pallette : {BLUE:string}) {
return pallette.BLUE;
}
whatBlueColor (Mycolors);
MyColors enum은 마치 일반적인 객체처럼 동작
whatBlueColor () 함수의 인자인 palette는 BLUE라는 속성을 갖는 객체, MyColors는 string 타입의 BLUE속성을 가지고 있기 때문에 코드가 정상 실행됨.
typeof 2022; // "number"
typeof "woowahan"; // "string"
typeof true; // "boolean"
typeof 0; // "object
: 타입스크립틍 = 값& 타입 공간 별도로 존재
typeof 연산자도 값에서 쓰일 때와 타입에서 쓰일 대 역할이 다름.
interface Person {
first: string;
last: string;
}
const person: Person = { first: "zig", last: "song" };
function email(options: person: Person; subject: string; body: string })
: 값에서 사용된 typeof는 자바스크립트 런타임의 typeof 연산자가 된다.
const v1 = typeof person; // 값은 object;
const v2 = typeof email; // 값은 'function'
: 반면 타입에서 사용된 typeof는 값을 일고 타입스크립트 타입을 반환
type T1 = typeof person; // 타입은 Person
type T2 = typeof email; // 타입은 options: { person: Person: subject: str
string; }) => void
person 변수가 interface Person 타입으로 선언, 타입공간에서의 typeof person은 Person을 반환
person변수가 interface Person 타입으로 선언 -> 타입 공간에서의 typeof person은 Person을 반환
email 함수 : 함수의 매개변수타입과 리턴 타입을 포함한 함수 시그니터 타입을 반환.
v1, v2 : const 키워드로 선언된 변수로 값이 할당될 공간,
값 공간의 typeof 는 피연산자인 person과 email의 런타임 타입으르 가리키는 문자열을 반환.
값에서 사용된 typeof 연산자는 자바스크립트 typeof 연산자와 동일하게 동작
도서 참조 : 우아한 타입스크립트 with 리액트