63171

[code]

    type Entry = [string, string]
    
[/code]

上記のような、 `Entry` 型が定義されていたとします。  
(実際的な想定としては、 config 系の型でよく見かける気がします。)

この type に対して、以下のコードは問題なく動きます。

[code]

    type Entry = [string, string]
    
    const entries1: Entry[] = [
        ['foo', 'bar']
    ]
    
    const concatenated1: Entry[] =
      entries1.concat([])
    
    console.log(concatenated1)
    // => [ [ 'foo', 'bar' ] ]
    
[/code]

一方、途中の `entries1` を省こうとすると、エラーになります。

[code]

    type Entry = [string, string]
    
    const concatenated2: Entry[] =
       [['foo', 'bar']].concat([])
    
    console.log(concatenated2)
    
[/code]

実行結果

[code]

    TS2322: Type 'string[][]' is not assignable to type 'Entry[]'.
      Type 'string[]' is missing the following properties from type 'Entry': 0, 1
    
    const concatenated2: Entry[] =
          ~~~~~~~~~~~~~
    
[/code]

# 質問

変数に束縛する前の即値に対して、型定義しながら変数代入したのと同等の型チェックを行う方法はありますでしょうか？

知っている中で近いのは、 `(expr as type)` の構文ですが、これは、プログラマが型を指定して、コンパイラは`expr`
についての型について関与しないための構文だと思っていて、型定義済み変数に代入したときの型チェックが実施できないと思っています。

# どういう場面でこれができると嬉しいか

たとえば、 `nuxt.config.ts` などでみかける、 config 系の巨大なオブジェクトの、１フィールド(ちょうど、この`Entry[]`
みたいな型定義を持つフィールド)を、環境変数を条件次第で concat
で追加させたい、などがやりたくなったとき、いちいちそのフィールドを変数に切り出すのは億劫です。できることなら、即値としてそのまま `concat`
につなげながらも、型チェックは行いたいと思ったので、質問しています。


CC BY-SA 4.0
2020-02-19T02:19:56.620
63164
2020-02-19T04:37:34.623
754
question
typescript
typescript で即値に対して型を制約したい


`Entry`を返す関数を定義して、型情報を補足してやるというのはどうでしょうか。

[code]

    type Entry = [string, string]
    
    const entry = (fst: string, snd: string): Entry => [fst, snd];
    
    const concatenated2: Entry[] =
        [entry('foo', 'bar')].concat([])
    
    console.log(concatenated2)
    
[/code]


CC BY-SA 4.0
2020-02-19T03:59:46.883
63170
2020-02-19T03:59:46.883
13199
63164
answer


config系に応用するのはやや困難ですが一応回答を残します。

根本的な原因は、`['foo', 'bar']`という式が型註釈無しでは`[string,
string]`ではなく`string[]`に推論されてしまうことです。これをタプル型が推論されるように矯正するには`as
const`を用います。これは`as`という構文を含みますが、あくまで推論方法を変えるフラグであり型を強制的に変えるものではないため`as
type`とは異なり安全です。

ただ、`as const`を使うと結果が`readonly [string,
string]`のような変更不可の型になるという副作用があります。そのため、元のコードにただ`as
const`を付加するだけではうまくいかず、`Entry`の型も`readonly`をつけて修正する必要があります。

そのため、`nuxt.config.ts`などの既存の型定義に合わせる目的では`as
const`を使いにくいかもしれません。最も理想的な解決策は、型定義を修正して`as const`対応にすることです。

[code]

    type Entry = readonly [string, string]
    
    const concatenated2: Entry[] =
       [['foo', 'bar'] as const].concat([])
    
    console.log(concatenated2)
    
[/code]


CC BY-SA 4.0
2020-02-19T04:11:21.450
63171
2020-02-19T04:37:34.623
2020-02-19T04:37:34.623
30079
30079
63164
answer