kanfutrooper
@kanfutrooper (masaomi)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

TypeScriptのエラーを解消したい

Q&A

Closed

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

//エラー文
Argument of type '"c"' is not assignable to parameter of type '"a" | "b"'.

//'c'の箇所に波線が表示される
wrappedObj1.set('c', '03') === false &&

if (wrappedObj1.get('b') === '04' && wrappedObj1.get('c') === undefined) {
type Obj01 = {
  a: string;
  b: string;
};
type K = keyof { a: string; b: string };

class ObjectWrapper <T extends Obj01>  {
  private _obj : T;

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

 get obj() {
    return { ...this._obj };
  }

set(key: K, val: string): boolean {
    if (this._obj[key] !== undefined) {
      this._obj[key] = val;
      return true;
    }
    return false;
  }

get(key:K ){
    return this._obj[key];
  }
  findKeys(val: unknown):string {
       return keys;
  }
}



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 &&   //'c'の箇所に波線が表示される
  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) {   //'c'の箇所に波線が表示される
  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

少し時間が立っていますが、改善方法についてはまだどなたも回答されていないようですので、提案させていただきます。

とはいえ、まず大前提として「改善方法」を答えるには「何をしたいか」を書いていただかないと回答できないという点にはご注意ください。
(おそらく他の方もそれで答えあぐねているのかと思います)

次回ご質問されるときは「何をしたいか」を必ず書くことをおすすめします。
というかそのためにQiitaは質問のテンプレートを用意しているので、消さずにちゃんと全部書くことをおすすめします。

以下では
「ObjectWrapperはabのkeyを必ずもつobjectのみをwrapし、しかしab以外のキーも操作できるようにしたい」
と仮定しています。

まず、エラーの原因は他の方が述べて頂いたとおりですので省略するとして、ObjectWrapperの定義は

type Obj01 = {
  a: string;
  b: string;
};
- type K = keyof { a: string; b: string };

class ObjectWrapper <T extends Obj01>  {
  private _obj : T;

  // ...

-  set(key: K, val: string): boolean {
+ set(key: keyof T, val: string): boolean { 
    if (this._obj[key] !== undefined) {
      this._obj[key] = val;
      return true;
    }
    return false;
  }

  // ...
}

のようにすると良いかと思います。
Tは {a: string; b:string} を継承する型ですので、そのほかの任意のkeyを含む可能性がありますが、key: keyof T とすることでそれらのkeyも第一引数として受け取ることができます。

また、setを呼び出すスクリプトについても

- const obj1 = { a: '01', b: '02' };
+ const obj1: {a: string; b: string; c?: string} = {a: '01', b: '02'}
const wrappedObj1 = new ObjectWrapper(obj1);

または

- const obj1 = { a: '01', b: '02' };
+ const obj1 = {a: '01', b: '02'} as {a: string; b: string; c?: string};
const wrappedObj1 = new ObjectWrapper(obj1);

などとする必要があります

typescriptでは変数の型注釈を省略した場合、代入文などから変数の型を自動で推測してくれるのですが、あくまで推測であって開発者の意図通りであるとは限らないことに注意してください。

ここでは、obj1の型注釈を省略したため、typescriptは代入文から
「aとbっていうキーだけがあって、それぞれ文字列が入るのね」
と推測し、

const obj1: {a: string, b: string} = { a: '01', b: '02' };

と同じ意味として扱っているということです。

そのため、その他のキーを今後セットする予定がある場合は、それを含めた型を明示的に指定する必要があるということになり、上記のような記述となります。

なお、cに限らず任意のキーをセットしたい場合は
{a: string; b: string; [key: string]: string}
という型宣言が使えます

2Like

Comments

  1. @kanfutrooper

    Questioner

    @bigen1925さん、回答、ありがとうございます!
    何をどうしたら良いかわからず、ずっと詰まっていたところでした!
    丁寧な解説つきの回答、本当にありがとうございました。

エラーの原因

keyof演算子の説明を読むと次のような仕様になっています。

type K = keyof { a: string; b: string };
// 上は次と同じ意味になる
type K = "a" | "b";

const k01: K = "a";
const k02: K = "b";
const k03: K = "c"; // error  Type '"c"' is not assignable to type '"a" | "b"'.

setメソッドの引数keyの型は"a" | "b"になりますが、それ以外が設定されているのでエラーになっています。

参考文献

1Like

Your answer might help someone💌