// Return값이 void
function a(): void{
return undefined;
}
// 메서드가 void
interface Human{
talk: () => void;
}
const human: Human = {
talk() {return 'abc';}
}
// 매개변수가 void
function a(callback:()=> void): void{}
a(()=>{
return 3;
});
declare
을 사용하면 함수의 구현부를 안 만들고 Type만 정의해둘 수 있다.
deflare function forEach(arr: number[], callback: (e1:number) => void):void;
let target: number[] = [];
forEach([1,2,3], e1 => {target.push(e1)});
forEach([1,2,3], e1 => target.push(e1));
// + 강제 타입 변환
const test = a as unknown as number; // test는 number로 바꿔라 내가 책임진다?
any
는 타입 체크를 아예 포기하는 것.
unknown
은 아직까지 타입이 확실하지 않아, 나중에 지정해서 쓸수있게끔 하는 것.
const a: A={
talk() {return 3;}
}
const b: unknown = a.talk();
(b as A).talk();
as
는 unknown
인 경우를 제외하고 가능하면 쓰지 않는 것이 좋다.
function numOrStr(a: number | string){
if(typeof a === 'number'){
a.toFixed(1);
} else{
a.charAt(3);
}
if(typeof a === 'string'){
a.charAt(3);
}
}
배열
function numOrNumArray(a: number | number[]){
if(Array.isArray(a)){
a.concat(4);
} else{
a.toFixed(3);
}
}
클래스
class typeA{
aaa(){}
}
class typeB{
bbb(){}
}
function aOrB(param: typeA | typeB){
// 여기서 typeA는 클래스 자체를 의미하는 것이 아니라 new typeA()을 의미한다.
if(param instanceof typeA){
param.aaa();
}
}
값으로 구분(보통 이걸 사용)
type B = {type: 'b', bbb: string};
type C = {type: 'c', ccc: string};
type D = {type: 'd', ddd: string};
function typeCheck(a: B | C | D){
if(a.type==='b'){
a.bbb;
} else if(a.type === 'c'){
a.ccc;
} else {
a.ddd;
}
}
속성으로 구분 : in
연산자를 사용
function typeCheck(a: B | C | D){
if('bbb' in a){
a.type;
} else if('ccc' in a){
a.ccc;
} else {
a.ddd;
}
}
⭐️⭐️⭐️ 객체를 만들 때 type을 만드는 습관을 가지자.
const human = {type: 'human'}
const dog = {type:'dog'}
const cat = {type:'cat'}
타입가드
: 변수나 객체의 타입을 더 구체적으로 추론하기 위해 사용하는 개념
타입을 구분해주는 커스텀 함수를 직접 만들 수 있다.
return타입에 is
가 들어가 있는 함수는 커스텀 타입 가드 함수이다.
어떨 때 쓰냐? if문 안에 써서 타입스크립트에게 정확한 타입을 가르쳐준다.
interface Cat { meow: number}
interface Dog { bow: number}
// a에 meow라는 고양이가 있다면 false;
function catOrDog(a: Cat | Dog): a is Dog {
if((a as Cat).meow) {
return false;
}
return true;
}
function pet(a: Cat | Dog){
if(catOrDog(a)){
console.log(a.bow);
}
if('meow' in a){
console.log(a.meow);
}
}
{}
, Object
: 모든 타입(객체를 뜻하는 것이 아님) + null,undefined는 제외한다.
unknown
unknown = {} | null | undefined
// 옛날 버전
const z: unknwon = 'hi';
if(z){
z; // z: unknown
}
// 최신 버전
if(z){
z; // z: {}
}
readonly
interface A{
readonly a: string;
}
const aaa: A = {a:'hello', b:'world'};
aaa.a = '123' // 여기서 오류난다. readonly속성이기 때문
인덱스드 시그니처
type A = {[key: string]: number}
const test: A = {a: 5, b: 3}
type B = 'Human' | 'Mammal' | 'Animal';
type Bc={[key in B]: number};
const testB: Bc = {Human:3};
// + interface에서는 |, &을 쓰지 못한다.
// 원본
class A{
a: string;
b: number;
constructor() {
this.a = '123';
this.b = 123;
}
}
// 축약
class A{
a:string='123';
b:number=123;
}
// Constructor가 필요한 이유 : 이렇게 쓴다.
class A{
a: string;
b: number;
constructor(a: string, b:number = 123) {
this.a = a;
this.b = b;
}
}
const a = new A('123');
매개변수에 기본값이 있으면 ?(Optional Chaining)을 쓰지 않아도 된다.
여기서 A는 new A('123')(인스턴스)을 가리킨다.
type AA = A;
const a: A = new A('123')
이건 클래스 자체인 A(본체?)를 가리킨다(typeof)
const b: typeof A = A;
implements
: 인터페이스를 구현한다.
interface A{
a: string;
b: string;
}
class B implements A{
a: string = '123';
b: string = 'world';
}
클래스 내부에서만 사용가능한 private
, protected
공통점 : new B()한 경우(인스턴스) 에서는 둘다 사용할 수 없다.
차이점 : 상속받았을 때 쓸수있냐 없냐
class B implements A{
private a: string = '123'
protected b: string = 'world';
}
class C extends B{
method(){
console.log(this.a); // 에러난다. 사용못함.
console.log(this.b);
}
}
public | protected | private | |
---|---|---|---|
클래스내부 | O | O | O |
인스턴스(newA()) | O | X | X |
상속클래스 | O | O | X |
: 지금 타입은 모르겠는데, 나중에 정한다.
타입을 변수처럼 만드는 것이 Generic
이다.
function add<T>(x: T, y:T): T{
}
function add2<T extends number, K extends string>(x:T, y:K): T{
//이런 방식으로 여러 개의 Generic을 만들고 제한을 둘 수도 있다.
}
add2(1,"제네릭2");
function add3<T extends {a:string}>(x:T): T{ return x };
add3({a: 'hello'})
function add4<T extends string[]>(x:T): T{ return x };
add3(['1','2','3'])
//함수 모양의 제한
function add5<T extends (a:string) => number>(x:T): T{ return x };
add5((a) => +a);