HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🚀
개발 노트
/
🎾
타입스크립트
/
🎑
객체의 프로퍼티에 접근, Index signature
🎑

객체의 프로퍼티에 접근, Index signature

 
TypeScript는 기본적으로 객체의 프로퍼티를 읽을 때,
string 타입의 key 사용을 허용하지 않는다.
반드시 string literal 타입의 key로 접근하거나,
객체의 타입 정의 시 index signiture를 선언해주어야 한다.
 
 
 
 
타입스크립트가 key의 타입으로 string literal만을 허용하는 이유
마우스 이벤트가 있다고 가정하자.
마우스 이벤트의 종류는 정해져있지만 
이벤트 이름을 String 타입으로 받을 때에는 오타 혹은 유효하지 않은
이벤트 이름으로 인해 발생하는 런타임 에러를 사전에 방지할 수 없다.
 
 
반면에, string literal 타입만을 허용하도록 하면
사전에 오타 혹은 여러가지 에러를 방지할 수 있다.
 
 

string 타입으로 객체의 프로퍼티에 접근하는 방법은?

 
index signature를 사용한다.
 

동적으로 Object에 property 추가

자바스크립트

key의 type으로 string, number, symbol를 이용하여
동적으로 객체에 프로퍼티를 추가할 수 있다.
만일 key에 그 외의 값이 들어온다면
JS는 런타임 이전에 toString()을 암묵적으로 호출한다.
 

타입스크립트

key의 type은 무조건 string 혹은 number이어야 하며,
toString()을 암묵적으로 호출하지 않는다.
 

Index signature의 단점

  • 모든 키를 허용한다.
    • 따라서, 객체에 없는 키를 사용하더라도 타입 체크에서 에러가 나지 않는다.
  • 특정 키가 필요하지 않다. { }와 같이 빈 객체도 할당이 된다.
  • 키마다 다른 타입을 가질 수 없다.
    • 따라서, 값의 타입을 유니온 타입을 사용해 확장시켜야 한다.
  • 타입스크립트의 언어 서비스를 제공받을 수 없다.
 
⇒ 가능하다면 Index signature의 사용을 피하라.
keys를 알고 있다면 Record 타입 혹은 매핑된 타입 사용을 고려해보자.
외부에서 받아오는 것과 같이 keys가 변동될 수 있다면 Index signature의 사용을 고려해보자.
 
타입의 keys들이 무엇이 될지 아는 경우에는
Index signature를 사용하는 것보다는 타입을 직접 선언하라.
번거롭더라도 타입의 안전성을 위해서는 직접 선언하라.
 

Record 타입

Mapped 타입

이미 선언된 타입의 프로퍼티에 어떤 조작을 가하여 새로운 타입을 만드는 것
Mapped 타입은 index signature와 관련이 없다.
in은 for...in의 축약형이라고 이해할 수 있다.
 
Mapped 타입은 조건부 타입을 이용하여
특정 조건에는 다른 타입을 만들어 줄 수도 있다.
notion image
 
외부로부터 데이터를 받아오는 상황에서
keys가 변동될 가능성이 있다면 Index signature의 사용을 고려해볼 수 있다.
하지만 keys가 변동될 수 있기 때문에
값의 타입에 null 혹은 undefined를 유니온 타입으로 넣어주는 것을 고려해야 한다.
특정 키가 언제든지 사라질 수 있기 때문이다.

참고자료

TypeScript | Index Signature - string key로 객체에 접근하기
JSX 파일을 TSX확장자로 바꾸어 작업을 하면서 객체를 활용하고 프로퍼티에 접근, 프로퍼티를 추가하는데에 자바스크립트와 타입스크립트 간에 차이가 있다는 것을 새롭게 알게되어 아래에 정리해보고자 한다. 먼저, 타입스크립트 오류 메시지 중 읽어봐도 감이 안잡혔던 오류를 해결한 방법을 통해 객체 활용 시 자바스크립트와 타입스크립트의 차이점에 대해 말하면 좋을 것 같다.
TypeScript | Index Signature - string key로 객체에 접근하기
https://velog.io/@yyeonjju/TypeScript-Index-Signature-string-key%EB%A1%9C-%EA%B0%9D%EC%B2%B4%EC%97%90-%EC%A0%91%EA%B7%BC%ED%95%98%EA%B8%B0
TypeScript | Index Signature - string key로 객체에 접근하기
인덱스 서명(Index Signature)
Object에 들어있는 다른 어떤 JavaScript 객체 참조도 문자열 로 액세스할 수 있습니다.
인덱스 서명(Index Signature)
https://radlohead.gitbook.io/typescript-deep-dive/type-system/index-signatures
인덱스 서명(Index Signature)
[이펙티브 타입스크립트+15] 동적 데이터에 인덱스 시그니처 사용하기
2장 타입스크립트의 타입 시스템 아이템 15 | 동적 데이터에 인덱스 시그니처 사용하기 3줄 요약 1. 가능하다면 인덱스 시그니처 사용을 피하자. 2. keys를 알고 있다면 Record 타입 혹은 매핑된 타입 사용을 고려해보자. 3. 외부에서 받아오는 것과 같이 keys가 변동될 수 있다면 인덱스 시그니처 사용을 고려해보자. 참고) 이펙티브 타입스크립트는 타입스크립트의 기본 그 이상을 다룹니다.
[이펙티브 타입스크립트+15] 동적 데이터에 인덱스 시그니처 사용하기
https://junghyunkim.tistory.com/m/entry/%EC%9D%B4%ED%8E%99%ED%8B%B0%EB%B8%8C-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B815-%EB%8F%99%EC%A0%81-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%97%90-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EC%8B%9C%EA%B7%B8%EB%8B%88%EC%B2%98-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
[이펙티브 타입스크립트+15] 동적 데이터에 인덱스 시그니처 사용하기
TypeScript에서 string key로 객체에 접근하기
TypeScript는 JavaScript의 관점에서 벗어나지 못한 상태로 접했을 때 매우 이상하게 느껴질 때가 있다. 이 포스트에서는 그런한 점 중 하나였던 index signatures에 대해서 이해하기 쉽게 설명하고자 한다. TypeScript는 기본적으로 객체의 프로퍼티를 읽을 때, string 타입의 key 사용을 허용하지 않는다. TypeScript가 처음이라면 아래 코드가 컴파일 에러를 만든다는 사실에 충격을 먹을 수도 있다.
TypeScript에서 string key로 객체에 접근하기
https://soopdop.github.io/2020/12/01/index-signatures-in-typescript/
TypeScript에서 string key로 객체에 접근하기
const a = "Hello World" // ⭐ 컴파일러는 이 변수를 string이 아닌 조금 더 좁은 타입으로 선언한 것으로 추론한다.(Literal Narrowing) // ⭐ a의 타입은 string 타입보다 훨씬 구체적인 "Hello World" 타입이다. let b = "Hello World" // ⭐ b변수는 let으로 선언되어 재할당될 수 있을 경우 어떤 문자열이든 넣을 수 있으며 그 경우의 수가 무한대 // ⭐ 그렇기 때문에 컴파일러는 이 변수를 string타입으로 추론한다. const c: string = "Hello World" //c 변수는 명시적으로 string 으로 선언했으므로 string 타입이다.
const obj = { foo: "hello" } let propertyName = "foo" //propertyName는 string 타입(let) console.log(obj[propertyName]) // 💣💣 컴파일 에러! //에러가 발생한 이유는 string literal 타입만 허용되는 곳(객체의 key)에 string 타입을 사용했기 때문
const obj = { foo: "hello", } const propertyName = "foo" console.log(obj[propertyName]) // ok! console.log(obj["foo"]) // ok! // ⭐⭐ 정상 컴파일 //⭐⭐ "foo"와 propertyName 모두 string literal type
<function handleEvent(event:string) {} // 이벤트 이름을 string 타입으로 받는다면 handleEvent("click") handleEvent("clock") // compile error : 오타. 컴파일 타임에 발견할 수 없다. handleEvent("hover") // compile error : 유효하지 않은 이벤트 이름. 컴파일 타임에 발견할 수 없다
type EventType = "mouseout" | "mouseover" | "click" //string literal 타입들의 조합 function handleEvent(event:EventType) {} handleEvent("click") handleEvent("hover") //compile error : EventType이라는 타입에 해당 string literal이 정의되지 않았기 떄문
interface Person { [key: string]: string | number; } const person: Person = {} person['name'] = '공공'; person['나이'] = 19;
type Record<K extends keyof any, T> = { [P in K]: T; };
type Vec3D = { [k in 'x' | 'y' | 'z']: number }
type ExternalType = { [key: string]: string | undefined; }