Templee_0309) TypeScript + string Key to Object

오범준·2021년 3월 7일

Error Message

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WidthSize'.
No index signature with a parameter of type 'string' was found on type 'WidthSize'.

// Width ( 24px default 는 제외 )
// 12, 14, 16, 18, 32 px
type WidthType = 'xxsmall' | 'xsmall' | 'small' | 'middle' | 'large';
type WidthSize = {
  [K in WidthType]: string;
};
const Width: WidthSize = {
  xxsmall: '12px',
  xsmall: '14px',
  small: '16px',
  middle: '18px',
  large: '32px',
};

// Height ( 24px default 는 제외 )
type HeightType = 'xxsmall' | 'xsmall' | 'small' | 'middle' | 'large';
type HeightSize = {
  [K in HeightType]: string;
};
const Height: HeightSize = {
  xxsmall: '12px',
  xsmall: '14px',
  small: '16px',
  middle: '18px',
  large: '32px',
};

const IconBlockWrapper = styled.div<{
  src: string;
  width?: string;
  height?: string;
}>`
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: ${(props) => (props.width ? Width[props.width] : '24px')};
  height: ${(props) => (props.height ? props.height : '24px')};
  background: url(${(props) => props.src});
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
`;

SQ

I am trying to use
'xxsmall', 'xsmall' .....
as an 'Key' of 'Width' OBJ

But, since ( ex) 'xxsmall' ) type is 'string' ,
it is throwing Error

Why ? why 'string' cannot be used as an 'index' above ?

link : https://soopdop.github.io/2020/12/01/index-signatures-in-typescript/

Because it is 'Typescript'

To be more exact ,
The reason behind above error is ,
you are using 'string type' to place where 'string literal' is only allowed

String vs String Literal

const a = "Hello World"
let b   = "Hello World"
const c : string = "Hello World"

1) 'b' 💗 String Type
decleard with 'let', which means any additional 'string' can be allocated to variable 'b'
2) 'c' : 'const' + ': string' 💗 string type
only 'string' type can be allocated to 'c'

3) 'a' ?

Literal Narrowing

compiler infer 'c' as more 'narrow' string type

that is,
'a' is "not" 💗 String Type

'a' is 💗 String literal Type

that is, only 'Hello World' can be allocated !

Using 'String Literal' as 'key' to approach 'Obj'

const obj = {
  foo: "hello",
}

const propertyName = "foo"

console.log(obj[propertyName]) // ok!
console.log(obj["foo"]) // ok!

it works fine . WHY ?
'propertyName' & 'obj' is 'literal type'


However

for (const key of Object.keys(obj)) {
  console.log(obj[key]) // compile error! key가 string타입이다.
}

Error !
WHY?
Because, Object.keys() return 'string[]' !

which means that 'key' in 'obj[key]' is 'string' type, not 'literal' type

Sample Solution : index signature

type ObjType = {
  [index: string]: string
  foo: string
  bar: string
}

const obj: ObjType = {
  foo: "hello",
  bar: "world",
}

const propertyName1 = "foo"
const propertyName2: string = "foo"

console.log(obj[propertyName1]) // ok
console.log(obj[propertyName2]) // ok

Solution

< Before >
type WidthSize = {
  [K in WidthType ]: string;
};

< After >
type WidthSize = {
  [K in WidthType as string]: string;
};

it means we are typing 'K' as 'string',
not 'string literal'

allow using 'string type key' to approach 'obj'

profile
Dream of being "물빵개" ( Go abroad for Dance and Programming)

0개의 댓글