ウェブサイト検索

TypeScript: 2番目のパラメーターの値を(1番目に基づいて)制限する方法


もし~のような定義があれば

type GroupIds = 'A'|'B'|'C'
type KeysA = 'A01' | 'A02'
type KeysB = 'B03' | 'B04'
type KeysC = 'C99'

それは次のように書けることは知っています

function MethodBy( p0:'A', p1:KeysA )
function MethodBy( p0:'B', p1:KeysB )
function MethodBy( p0:'C', p1:KeysC )
function MethodBy( p0, p1 )
{
    //implement
}

でも、このようなものがあるかどうか聞きたいです

//maybe define a mapper
type IMapForKeys<T extends GroupIds> =
{
    [ key: 'A' ]: KeysA
    [ key: 'B' ]: KeysB
    [ key: 'C' ]: KeysC
}

//then method can write like...
function MethodBy<T extends GroupIds>( p0:T, p1:IMapForKeys[T] )
{
    //implement
}

それとも何か回避策はありますか、ヒントをもらえると嬉しいです、ありがとう :)

回答 #1

私が知っている最も近い方法は、GroupIds の値を手動で IMapForKeys のキーとして使用することです。

type GroupIds = 'A' | 'B' | 'C'
type KeysA = 'A01' | 'A02'
type KeysB = 'B03' | 'B04'
type KeysC = 'C99'

type IMapForKeys = {
  'A': KeysA;
  'B': KeysB;
  'C': KeysC;
}

function MethodBy<T extends GroupIds>(p0: T, p1: IMapForKeys[T]) {}

MethodBy の使用意味は正しいです。

MethodBy('D', 'A01') // 'D' not allowed
MethodBy('A', 'A01') // allowed
MethodBy('A', 'B03') // 'B03' not allowed

もし新しいキーが GroupIds に追加されると、MethodBy の2番目のパラメータは Type 'T' cannot be used to index type 'IMapForKeys'. という型チェックに失敗します。

もし未知のキーが IMapForKeys に追加された場合、それを MethodBy の最初のパラメータとして使用することはできません。なぜなら、MethodBy は GroupIds のメンバーを必要とするからです。


可能であれば、型を再構築して、IMapForKeysからGroupIdsやKeysの型を引き出すようにすることをお勧めします。逆ではなく。これにより、型の信頼できる単一の情報源があるため、よりクリーンになると思います。

interface IMapForKeys {
  'A': 'A01' | 'A02';
  'B': 'B03' | 'B04';
  'C': 'C99';
}

type GroupIds = keyof IMapForKeys
type KeysA = IMapForKeys['A']
type KeysB = IMapForKeys['B']
type KeysC = IMapForKeys['C']

function MethodBy<T extends GroupIds>(p0: T, p1: IMapForKeys[T]) {}

MethodBy('D', 'A01') // 'D' not allowed
MethodBy('A', 'A01') // allowed
MethodBy('A', 'B03') // 'B03' not allowed

回答 #2

考えられる解決策の一つは、識別ユニオンを使用することです。以下は例です:

type MyTypeA = {
    p0: "A";
    p1: 'A01' | 'A02';
}

type MyTypeB = {
    p0: "B";
    p1: 'B03' | 'B04';
}

type MyTypeC = {
    p0: "C";
    p1: 'C99';
}

function MethodBy(args: MyTypeA | MyTypeB | MyTypeC) {
    //
}

//e.g.
MethodBy({ p0: "B", p1: "B04" });   //OK
MethodBy({ p0: "B", p1: "C99" });   //compile error