프론트엔드 개발/Typescript

타입스크립트 에러) Element implicitly has an 'any' type because expression of type 'string' can't be used to index type / indexable 타입

Ella Seon 2023. 3. 16. 01:31

✅경축 🏌️25시간만에 에러 해결 ㅠㅠㅠㅠ

타입스크립트 + 리액트 프로젝트를 하던 중 버튼 공통컴포넌트를 만들면서 타입스크립트에서 에러가 났다...

타입스크립트를 안썼다면 금방 만들었을 버튼...25시간만에 에러를 해결해서 너무 행복하다😂

 

1) 해결한 에러 메세지

Type 'undefined' cannot be used as an index type.

2) 원인 

인덱스 시그니처(Object[key]) 형태로 객체 접근 시 에러

✅에러 해결 과정

지난 시간에(아래 블로그 참고) 버튼 컴포넌트를 만들었다.

https://ella951230.tistory.com/entry/%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-styled-components-theme-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0

 

리액트+타입스크립트) styled-components theme 설정하기

✅ 글을 쓰게 된 이유 - 버튼 컴포넌트를 만드려고 하는데 타입스크립트에서 theme을 어떻게 설정해야할지 몰라서 정리해본다. ✅ GlobalStyle VS theme 그동안 프로젝트에서 GlobalStyle 에서 아래와 같이

ella951230.tistory.com

버튼은 색상이 가지각색이다. 한개의 색상이 있는 버튼만 있다면 재사용성이 줄어든다. 

그래서 theme.ts에 저장한 colors 를 이용해서 여러 색상이 있는 버튼을 만들려고 한다.

 

그래서 아래까지 작업을 완료하였다.

 

// App.tsx

 theme.ts에 있는 green 색상을 props로 Button 컴포넌트에 넘겨주자

//Button.tsx

색상을 넘겨주었으니 안에 버튼 안의 들어갈 글자를 children 으로 설정하고

props 들의 타입을 interface로 지정해준다.

그리고 버튼의 스타일 컴포넌트에 버튼 color, 버튼 글자인 children을 넘겨준다.

 //style.ts

 받아온 props color과 children을 또 interface로 타입을 지정해준다.

하지만, props.theme.colors[props.color] 에서 에러가 났다.

인덱스 시그니처(Object[key]) 형태로 객체 접근시에 에러가 발생한다..

 

✅에러메세지
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ green: string; lightGray: string; darkGray: string; }'.
  No index signature with a parameter of type 'string' was found on type '{ green: string; lightGray: string; darkGray: string; }'

챗 GPT로 에러문을 해석해보니
이는 'string' 형식의 표현식을 인덱스로 사용할 수 없기 때문에 요소가 암시적으로 'any' 형식으로 간주됩니다.
'문자열' 형식의 매개변수를 사용하는 인덱스 시그니처(index signature)가 형식에 발견되지 않았습니다.

 

selected 변수를 마우스에 대보면 const selected: any 가 나온다...

any 타입이라고 왜 에러메세지가 나옴??

tsconfig 의 "noImplicitAny" : true 로 설정했기에 에러메세지가 나왔다. (any라는 타입이 의도치 않게 발생할 경우 에러를 띄워주는 설정)

 

그렇다면 아래 selected가 왜 any 타입으로 나온걸까? 프로퍼티에 접근할 때 어떤 타입인지 확인할 수 없어서 암묵적으로 any 타입을 사용했다고 한다.  props 로 받아오는 theme.ts 에 있는 colors 객체에 암묵적으로 타입이

const colors{ green: string; lightGray: string; darkGray: string; }  이렇게 추론이 되었는데.. 왜 string 타입은 [props.color]에 들어갈 수 없는거지??

 

빨간 줄의 원인은 'Typescript IndexAble' 이다. 

즉... Typescript는 javascript 처럼..Obeject[key] 로 적기만 하면 인식을 못한다...

타입스크립트 네이놈!! 정말 까다로운 아이였구나

 

이를 해결하기 위해서는 IndexAble 타입에 대해서 알아야한다.


🔶 IndexAble 타입

- 자바스크립트는 객체의 프로퍼티에 접근할 때 문자열로 접근 할 수 있다. [] 을 이용하여 접근할 수 있다.

// ES6
let obj = {};
obj['str'] = 'string';
console.log(obj['str']); // string

- 그리고 객체의 프로퍼티로 지정할 수 있다.

let key = {};
let obj = {};
obj[key] = '객체안에 프로퍼티로 지정 가능해';
console.log(obj[key]); //객체안에 프로퍼티로 지정 가능해
console.log(obj) // {[object Object]: '객체안에 프로퍼티로 지정 가능해'}

- 자바스크립트 색인의 동작방식에 의해 객체의 색인에 접근할 때 내부적으로 toString() 메서드를 호출하여 문자열로 변형된 값을 통해 접근한다. 

let key = {
    toString() {
        console.log('toString 이 작동돼');
    }
};
let obj = {};
obj[key] = 'Key is obj'; //toString 이 작동돼
//'Key is obj'

 


위의 예제에서처럼, 자바스크립트는 객체의 키는 string,symbol만 가능한데 숫자나 다른타입의 값을 키로 사용하고자 하면 자바스크립트 런타임시 문자열로 변환된다.

 

stirng 타입으로 변환.. 응 알겠어 근데.. Object[key] 에 key가 string 타입으로 들어가면 안된다는거야?

 

응 안돼... 이래서 Object[key]로 접근할때 타입을 인식 못하고 any 타입이 나왔던 거구나

TypeScript는 기본적으로 객체의 프로퍼티를 읽을 때, 
string타입의 key 사용을 허용하지 않는다.
반드시 string literal 타입의 key로 접근하거나 객체의 타입 정의 시, 아래에서 설명할 index signiture를 선언해주어야한다.
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

 

✅ 에러 해결 방법

theme.ts 파일에 가서  colors 객체에 index signature 타입을 지정해준다.

index signature은 object 안에 속성이 많을때 사용되는걸로

[key:string]:string key값은 string 으로, value 값도 string 이라는 뜻이다. 

key 부분은 작명이 된다.

 

인덱스 시그니처는 객체가 {key,value} 형식이며 Key와 Value의 타입을 정확하게 명시해야 하는 경우 사용할 수 있다.

 

 

 

참고자료 

 

https://velog.io/@shin6403/Typescript-JS%EB%8A%94-%EC%A0%95%EB%A7%90-%EC%A2%8B%EC%9D%80-%EC%95%84%EC%9D%B4%EC%98%80%EA%B5%AC%EB%82%98feat.-Indexable

 

Typescript | JS는 정말 좋은 아이였구나(feat. Indexable)

#Intro IndexAble을 설명하기 앞서 간단한(?) 코드카타를 하고 넘어가자. >#### 문제) ['2020','Jan','23'] 의 배열을 '2020-01-23'로 만드시오. 프로젝트를 진행하고 있었다. 오랜만에 로직을 짤 일이 있어서 코

velog.io

https://medium.com/%EC%98%A4%EB%8A%98%EC%9D%98-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%97%90%EC%84%9C-object-object-%EA%B0%80-%EB%8C%80%EC%B2%B4-%EB%AD%98%EA%B9%8C-fe55b754e709

 

자바스크립트에서 [object Object] 가 대체 뭘까?

Object.prototype.toString 에 대한 깊은 설명

medium.com

https://darrengwon.tistory.com/117

 

interface 기초와 활용 (Read-only properties, Indexable Types, extends)

interface 기본 (https://typescript-kr.github.io/pages/interfaces.html) (typescript-handbook-ko.org/pages/interfaces.html) interface는 object의 type을 체크해주는 ts의 고유한 문법이다. object 각 요소들의 타입을 따질 때 편리하

darrengwon.tistory.com

https://www.youtube.com/watch?v=itDNYvs_rVs&list=PLV6pYUAZ-ZoFwOspuVHBvmhQRalqvj7Jf&index=22