Object Types[Typescript]

SnowCat·2023년 2월 15일
0

Typescript - Handbook

목록 보기
6/9
post-thumbnail

Property Modifiers

  • 객체에서의 속성은 타입, 속성의 optional 여부, 속성의 쓰기 여부를 확인할 수 있음

Optional Properties

  • 객체에는 선택적으로 가질 수 있는 프로퍼티가 있으며, 이는 이름에 물음표를 추가함으로서 구현 가능
interface PaintOptions {
  shape: Shape;
  xPos?: number;
  yPos?: number;
}
  • Optional Properties가 들어오면 해당 값은 undefined가 들어올 수 있음에 주의
// 해결책 1 - 타입 체크
function paintShape(opts: PaintOptions) {
  let xPos = opts.xPos === undefined ? 0 : opts.xPos;
  let yPos = opts.yPos === undefined ? 0 : opts.yPos;
  // ...
}

// 해결책 2 - 기본값 설정
function paintShape({ shape, xPos = 0, yPos = 0 }: PaintOptions) {
  let xPos = opts.xPos === undefined ? 0 : opts.xPos;
  let yPos = opts.yPos === undefined ? 0 : opts.yPos;
  // ...
}

//구조분해 문법 내부에 타입을 작성하지 말 것
function draw({ shape: Shape, xPos: number = 100 /*...*/ }) {
  render(shape); //Cannot find name 'shape'. Did you mean 'Shape'?
  render(xPos); //Cannot find name 'xPos'.

readonly Properties

  • readonly를 이름 앞에 붙여 읽기전용 속성으로 처리 가능
  • 타입검사중에 값이 변경되는 것은 막아주지만, 런타임 중에 값이 바뀌는 것은 막아주지 않음에 주의
interface SomeType {
  readonly prop: string;
}
 
function doSomething(obj: SomeType) {
  console.log(`prop has the value '${obj.prop}'.`);
 
  // Cannot assign to 'prop' because it is a read-only property.
  obj.prop = "hello";
}
  • 객체도 readonly 설정이 가능하지만, 객체에 const를 쓴것과 비슷하게 객체 내부의 값은 변경 가능함에 주의
interface Home {
  readonly resident: { name: string; age: number };
}
 
function visitForBirthday(home: Home) {
  // 가능
  console.log(`Happy birthday ${home.resident.name}!`);
  home.resident.age++;
}
 
function evict(home: Home) {
  // Cannot assign to 'resident' because it is a read-only property.
  home.resident = {
    name: "Victor the Evictor",
    age: 42,
  };
}
  • 값을 할당할 때 readonly여부는 타입에서 고려되지 않음
interface Person {
  name: string;
  age: number;
}
 
interface ReadonlyPerson {
  readonly name: string;
  readonly age: number;
}
 
let writablePerson: Person = {
  name: "Person McPersonface",
  age: 42,
};
 
// 타입이 같다고 간주
let readonlyPerson: ReadonlyPerson = writablePerson;
 
console.log(readonlyPerson.age); // prints '42'
writablePerson.age++;
// readonly임에도 불구하고 shallow copy를 했기에 writablePerson 값 변화에 영향을 받게 됨
console.log(readonlyPerson.age); // prints '43'

Index Signatures

  • 배열의 반환값으로 무엇이 들어올지 알 수 있는 경우 index signatures를 사용할 수 있음
interface StringArray {
  [index: number]: string;
}
 
const myArray: StringArray = getStringArray();
const secondItem = myArray[1]; //string
  • index signatures 를 사용한 경우 그 밑의 일반 속성들도 전부 index signatures의 반환 타입을 따라야 함
interface NumberDictionary {
  [index: string]: number;
  length: number;
  // Property 'name' of type 'string' is not assignable to 'string' index type 'number'.
  name: string;
}

// ok
interface NumberOrStringDictionary {
  [index: string]: number | string;
  length: number;
  name: string;
}

Extending Types

  • 인터페이스는 extends 구문을 통해 타입의 확장이 가능
interface BasicAddress {
  name?: string;
  street: string;
  city: string;
  country: string;
  postalCode: string;
}
 
interface AddressWithUnit extends BasicAddress {
  unit: string;
}

// 두개 이상의 타입도 상속 가능
interface Colorful {
  color: string;
}
 
interface Circle {
  radius: number;
}
 
interface ColorfulCircle extends Colorful, Circle {}
 
const cc: ColorfulCircle = {
  color: "red",
  radius: 42,
};

Intersection Types

  • 여러 인터페이스들을 동등하게 결합해서 새로운 타입을 생성할수도 있음
interface Colorful {
  color: string;
}
interface Circle {
  radius: number;
}
 
type ColorfulCircle = Colorful & Circle; //color, redius 속성을 가짐

intersection과 extend와의 차이

Generic Object Types

  • 하나의 객체 형태에 여러 타입이 올 수 있으면 제네릭 타입을 사용해 객체를 정의할 수 있음
interface Box<Type> {
  contents: Type;
}

//제네릭 함수와의 결합
function setContents<Type>(box: Box<Type>, newContents: Type) {
  box.contents = newContents;
}
  • 제네릭을 사용한 객체에도 type aliases 적용 가능
type OrNull<Type> = Type | null;
 
type OneOrMany<Type> = Type | Type[];
 
type OneOrManyOrNull<Type> = OrNull<OneOrMany<Type>>;// OneOrMany<Type> | null
 
type OneOrManyOrNullStrings = OneOrManyOrNull<string>;// OneOrMany<string> | null

The Array Type

  • 배열 타입들은 전부 Array<Type> 타입으로 대체 가능함, 여기서 Array 타입은 제네릭 타입임
    비슷하게 여러 타입들이 들어올 수 있는 Map, Set, Promise의 경우 각각 Map<K, V> Set<T> Promise<T> 형식으로 타입이 정의되어 있음
function doSomething(value: Array<string>) {
  // ...
}
 
let myArray: string[] = ["hello", "world"];
 
// Array<string>와 string[]은 같은 타입
doSomething(myArray);
doSomething(new Array("hello", "world"));
  • 다른 타입들과 유사하게 앞에 Readonly를 붙여 읽기 전용의 배열을 만들수도 있음
// readonly string[]과 동일한 타입
function doStuff(values: ReadonlyArray<string>) {
  const copy = values.slice();
  console.log(`The first value is ${values[0]}`);
 
// Property 'push' does not exist on type 'readonly string[]'.
  values.push("hello!");
}

// consturctor 사용 불가
new ReadonlyArray("red", "green", "blue");
// 'ReadonlyArray' only refers to a type, but is being used as a value here.

// 배열을 직접 할당해주어야함
const roArray: ReadonlyArray<string> = ["red", "green", "blue"];
  • 배열에서는 객체와 다르게 readonly 배열의 값 할당 불가능
let x: readonly string[] = [];
let y: string[] = [];
 
x = y; // ok
// The type 'readonly string[]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
y = x;

Tuple Types

  • 배열에 여러 타입의 값이 동시에 들어오고, 각 타입이 들어오는 위치를 정확하게 안다면 튜플 타입의 사용이 가능함
  • readonly와 같이 런타임중에는 적용되지 않음
type StringNumberPair = [string, number];
function doSomething(pair: StringNumberPair) {
  const a = pair[0]; //string
  const b = pair[1]; //number
  // Tuple type '[string, number]' of length '2' has no element at index '2'.
  const c = pair[2];

}
 
doSomething(["hello", 42]);
  • 튜플 타입에 맞다면 구조분해 문법도 사용 가능
function doSomething(stringHash: [string, number]) {
  const [inputString, hash] = stringHash;
  console.log(inputString); //string
  console.log(hash); //number
}
  • 필요하다면 optional properties도 사용 가능
type Either2dOr3d = [number, number, number?];
 
function setCoordinate(coord: Either2dOr3d) {
  const [x, y, z] = coord; //z: number | undefined
 
  //length: 2 or 3
  console.log(`Provided coordinates had ${coord.length} dimensions`);
}
  • 타입의 위치는 알지만 갯수를 알지 못할 때에는 spread 연산자를 사용
type StringNumberBooleans = [string, number, ...boolean[]];
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];

// 함수의 인자로 들어갈 때에는 다음과 같이 작성
function readButtonInput(...args: [string, number, ...boolean[]]) {
  const [name, version, ...input] = args;
  // ...
}

// 다음 표현과 결국 같은 말
function readButtonInput(name: string, version: number, ...input: boolean[]) {
  // ...
}
  • 튜플도 readonly 속성 적용 가능
function doSomething(pair: readonly [string, number]) {
  pair[0] = "hello!"; //Cannot assign to '0' because it is a read-only property.
  
 // 배열에 const를 붙이면 readonly tuple로 취급됨
let point = [3, 4] as const;
 
function distanceFromOrigin([x, y]: [number, number]) {
  return Math.sqrt(x ** 2 + y ** 2);
}

/*
Argument of type 'readonly [3, 4]' is not assignable to parameter of type '[number, number]'.
  The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type '[number, number]'.

*/
distanceFromOrigin(point);
}

출처:
https://www.typescriptlang.org/docs/handbook/2/objects.html

profile
냐아아아아아아아아앙

0개의 댓글