kanfutrooper
@kanfutrooper (masaomi)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

TypeScriptのエラーを解消したい

解決したいこと

TypeScriptのclass文法を勉強しています。
下記4ヶ所にエラーの表示が出ます。
調べてエラーが改善しません。
何方か改善方法を教えてください。

発生しているエラー

① Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Object'.
  No index signature with a parameter of type 'string' was found on type 'Object'.
② Property 'a' does not exist on type 'Object'.
③ Property 'b' does not exist on type 'Object'.
typescript.js
class ObjectWrapper {
  private _obj;

  /***
   * 引数のオブジェクトのコピーを this._objに設定
   */
  //変更前 constructor(_obj: Object) {}
  constructor(_obj: Object) {
    this._obj = _obj;
  }
  /**
   * this._objのコピーを返却
   * @return Object
   */
  //変更前 get obj() {}
  get obj() {
    return this._obj;
  }
  /**
   * this._obj[key] に valを設定。keyがthis._objに存在しない場合、falseを返却
   * @param key オブジェクトのキー
   * @param val オブジェクトの値
   */
  //変更前set(key, val): boolean {}
  set(key: string, val: string): boolean {
    if (this._obj[key] !== undefined) {      // ① のエラーが表示 
      console.log(typeof this._obj);
      console.log(typeof key);
      this._obj[key] = val;                                     // ① のエラーが表示 
      return true;
    }
    return false;
  }

  /**
   * 指定したキーの値のコピーを返却
   * 指定のキーが存在しない場合 undefinedを返却
   * @param key オブジェクトのキー
   */
  //変更前get(key) {}
  get(key: string) {
    return this._obj[key];
  }
  /**
   * 指定した値を持つkeyの配列を返却。該当のものがなければ空の配列を返却。
   */
  //findKeys(val: unknown) {}
  findKeys(val: unknown): unknown[] {
    return keys;
  }
}

/**
 * check script
 * 完成したら、以下のスクリプトがすべてOKになる。
 */
const obj1 = { a: '01', b: '02' };

const wrappedObj1 = new ObjectWrapper(obj1);

if (wrappedObj1.obj.a === '01') {                                 // ② のエラーが表示 
  console.log('OK: get obj()');
} else {
  console.error('NG: get obj()');
}

if (
  wrappedObj1.set('c', '03') === false &&
  wrappedObj1.set('b', '04') === true &&
  wrappedObj1.obj.b === '04'                                           // ③ のエラーが表示 
) {
  console.log('OK: set(key, val)');
} else {
  console.error('NG: set(key, val)');
}

if (wrappedObj1.get('b') === '04' && wrappedObj1.get('c') === undefined) {
  console.log('OK: get(key)');
} else {
  console.error('NG: get(key)');
}

const obj2 = { a: '01', b: '02', bb: '02', bbb: '02' };
const wrappedObj2 = new ObjectWrapper(obj2);
const keys = wrappedObj2.findKeys('02');
if (
  wrappedObj2.findKeys('03').length === 0 &&
  keys.includes('b') &&
  keys.includes('bb') &&
  keys.includes('bbb') &&
  keys.length === 3
) {
  console.log('OK: findKeys(val)');
} else {
  console.error('NG: findKeys(val)');
}

0

2Answer

以下で解決します。

interface MyObj { [key: string]: string }
class ObjectWrapper {
  private _obj: MyObj;
  constructor(_obj: MyObj) {
    this._obj = _obj;
  }
  // 以下省略
}

エラーの内容は
Object型だと文字列のindexはないから、any型として扱うよ
Object型のプロパティにaなんてないよ
Object型のプロパティにbなんてないよ

TypeScriptを使うのであればObject型はできるだけ使わないほうが良いです。
interface MyObj { [key: string]: string }ではkeyとvalueの両方がstring型の連想配列の型を定義しています。
なお、今回のコードであればtype MyObj = { [key: string]: string }でも大丈夫です。
また、実行時にfindKeysでエラーになりますが、そこの解決はしていません。

0Like

Comments

  1. @kanfutrooper

    Questioner

    @h_kono0707さん、解説付きの回答、ありがとうございます!
    返信が遅くなりまして、申し訳ございません。
    何とか上記のエラーは解決する事ができました。
    この度は、丁寧な解説付きの回答、本当にありがとうございました!

なんとなくやりたいことはイメージできますが,特にクラスを設計する際は機能と要件を明確にしておくことが必要です.質問にも必ず書きましょう.
JavaScriptライクな言語は特にエラーをなくすためだけにソースを改修していると必ず痛い目を見ます.

if (wrappedObj1.obj.a === '01') {

とか

if (
    //...
    wrappedObj1.obj.b === '04' // ③ のエラーが表示 
) {

みたいなことをしているあたり,
プロパティaとbは最低限持っているということなら,どこかでそれを明示しないといけません1.
↓のように_objの大元に自作のtypeを指定するか,class側でアクセスを保証しましょう.

// aとbはstringを格納できるプロパティ
type BaseObject = {
    a: string
    b: string
}

class ObjectWrapper {
    private _obj: BaseObject;

    constructor(_obj: BaseObject) {
        this._obj = _obj;
    }

//...

なおかつ,動的なパラメータがkeyとして渡されることが予測される場合は,そのように定義しておく必要があります.

type BaseObject = {
    a: string
    b: string
    [key: string]: string // 任意のstringなkeyでアクセスできる.
}
// ...
    set(key: string, val: string): boolean {
        if (this._obj[key] !== undefined) { // アクセス可能
            console.log(typeof this._obj);
            console.log(typeof key);
            this._obj[key] = val;
            return true;
        }
        return false;
    }

それ以上に一番ダメなのがfindKeysで,setterにはstringしか受け付けないのにunknownを取ったり,返すkeysはグローバルにあるkeysだったり,そもそも値を参照している様子が無かったりといろいろロジックが破綻しています.
動き方がわからないならともかく(よくはないけど),ロジック上うまく動かないと分かっているコードを動かすべきではありません.

  1. そもそもの話,元のソースのように「aとbは当然持ってるだろ」というJavaScriptの甘えを許さないのがTypeScriptであり,これは他の型付け言語では最初からケアしておかなければならない要素でもあります.anyですべてを黙殺するという荒業ができなくはないですが,最終手段と考えましょう.

0Like

Comments

  1. @kanfutrooper

    Questioner

    @Vercleneさん、解説付きの回答、ありがとうございます!
    返信が遅くなりまして、申し訳ございません。

    何とか上記のエラーは解決する事ができたのですが、
    findKeysの箇所のソースコードの書き方がどのように書いたら良いかわからず、
    エラーが出ないように表記したらこのようになってしまいました。

    この度は、丁寧な解説付きの回答、本当にありがとうございました!

Your answer might help someone💌