質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

解決済

2回答

279閲覧

TypeScriptで定義したオブジェクトに新しい要素を追加できないようにしたい

moimoi_sushi

総合スコア26

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

0クリップ

投稿2021/06/30 05:07

TypeScriptでオブジェクトをより安全に扱いたいため質問です。

const data = ['logo.png','search.png','stock.png'] //本当は画像データを想定した文字列 interface objType { [key: string]: string; } const nameObj: objType = { 'logo': "", 'search': "" }; data.map((name: string) => { const imgName = name.split(".")[0]; nameObj[imgName] = name; return; }); console.log(nameObj);

nameObj は入ってくることが事前にわかっている画像データ名のオブジェクトです。
キーに 'logo', 'search' が入っておりそれ以外は入れたくありません。

ソースコード(TSのPlayground)

問題

上のコードを実行すると

{ "logo": "logo.png", "search": "search.png", "stock": "stock.png" }

が返ってきてしまいます。
キーに 'logo', 'search' のみが入り他のプロパティは入ってきて欲しくありません。(エラーになって欲しい)。

試したこと

interface objType { [key: string]: string; }

interfaceの定義が[key: string]プロパティ形式であればなんでも入るようにしていることが原因ではあります。
しかし

interface objType { "logo": string, "search": string }

とすると、

nameObj[imgName] = name;

の行に対して、

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

上のように未定義の型が入ってきてしまうと型のメッセージが当然ながら出てきてしまいます。

質問

どのようにすれば nameObj に入れる型を限定しながら data.map(省略) を回す処理ができるようになるでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

以下のようなコードがあったとしましょう。

TypeScript

1interface objType { 2 'logo': string, 3 'search': string 4} 5 6function foo(imgName: string, name: string): objType { 7 let nameObj: objType = {'logo': '', 'search': ''} 8 nameObj[imgName] = name 9 return nameObj 10}

TypeScript: TS Playground - An online editor for exploring TypeScript and JavaScript
リンク先で動かすと同じようなところでエラーが出ています。なぜかと言うと、objType のキーは string 型ではなく 'logo' | 'search' というユニオン型になっています。そもそも型が違うためコンパイルできません。ではどのようにして objType にアクセスするかですが、答えは簡単で if で分岐をし、キーを直接書くことです。

TypeScript

1function foo(imgName: string, name: string): objType | null { 2 let nameObj: objType = {'logo': '', 'search': ''} 3 4 if(imgName === 'logo'){ 5 nameObj['logo'] = name 6 }else if(imgName === 'search'){ 7 nameObj['search'] = name 8 }else{ 9 return null 10 } 11 return nameObj 12}

TypeScript のわかりにくい点のひとつなんですが、bar['baz'] と書いた場合 'baz' は string 型か 'baz' を含むユニオン型のどちらかになります。この場合は interface でキーの型を決めていますから後者であるとコンパイラが解釈してくれます。また、関数の戻り値の型が objType | null
となっている点にも注意しましょう。imgName'logo''search' 以外の場合は null にするようにしてみました(もちろんここは好みの処理に変えて構いません)。実際の動きは関数 foo
の戻り値を console.log() して確認してみてください。

投稿2021/07/01 11:45

A_kirisaki

総合スコア2853

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

遅レスすみません。結論としてはif文で可能性を打ち消す形でしか難しそうだったので以下のようにしました。

他に方法ありそうな気もしますがひとまずkeyにユニオン型を適用させたい場合はIF文を使ってみようと思います。

typescript

1const data = ['logo.png','search.png','stock.png'] //本当は画像データを想定した文字列 2 3interface objType { 4 'logo' : string, 5 'search' : string 6} 7 8const nameObj: objType = { 9 'logo': "", 10 'search': "" 11}; 12 13data.map((name: string) => { 14 const keyN = name.split(".")[0]; 15 if (keyN !== 'logo' && keyN !== 'search' ) return; 16 nameObj[keyN] = name; 17 18 return; 19}); 20

投稿2021/07/11 15:15

編集2021/07/11 15:18
moimoi_sushi

総合スコア26

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

moimoi_sushi

2021/07/11 15:19

if (keyN !== 'logo' && keyN !== 'search' ) return; で他の型の可能性を打ち消しているため自ずとkeyNは logo | search のユニオン型になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問