feat(schema): add type hints for runtime config (#18652)

This commit is contained in:
Daniel Roe 2023-02-06 15:27:35 -08:00 committed by GitHub
parent 85881b462b
commit 01076d144f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 2 deletions

View File

@ -9,10 +9,59 @@ export type { SchemaDefinition } from 'untyped'
type DeepPartial<T> = T extends Function ? T : T extends Record<string, any> ? { [P in keyof T]?: DeepPartial<T[P]> } : T
type ExtractUpperChunk<T extends string> = T extends `${infer A}${infer B}`
? A extends Uppercase<A>
? B extends `${Uppercase<string>}${infer Rest}`
? B extends `${infer C}${Rest}`
? `${A}${C}${ExtractUpperChunk<Rest>}`
: never
: A
: ''
: never
type SliceLast<T extends string> = T extends `${infer A}${infer B}`
? B extends `${infer C}${infer D}`
? D extends ''
? A
: `${A}${C}${SliceLast<D>}`
: ''
: never
type UpperSnakeCase<T extends string, State extends 'start' | 'lower' | 'upper' = 'start'> = T extends `${infer A}${infer B}`
? A extends Uppercase<A>
? A extends `${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0}`
? `${A}${UpperSnakeCase<B, 'lower'>}`
: State extends 'lower' | 'upper'
? B extends `${SliceLast<ExtractUpperChunk<B>>}${infer Rest}`
? SliceLast<ExtractUpperChunk<B>> extends ''
? `_${A}_${UpperSnakeCase<B, 'start'>}`
: `_${A}${SliceLast<ExtractUpperChunk<B>>}_${UpperSnakeCase<Rest, 'start'>}`
: B extends Uppercase<B>
? `_${A}${B}`
: `_${A}${UpperSnakeCase<B, 'lower'>}`
: State extends 'start'
? `${A}${UpperSnakeCase<B, 'lower'>}`
: never
: State extends 'start' | 'lower'
? `${Uppercase<A>}${UpperSnakeCase<B, 'lower'>}`
: `_${Uppercase<A>}${UpperSnakeCase<B, 'lower'>}`
: Uppercase<T>
const message = Symbol('message')
export type RuntimeValue<T, B extends string> = T & { [message]?: B }
type Overrideable<T extends Record<string, any>, Path extends string = ''> = {
[K in keyof T]?: K extends string
? T[K] extends Record<string, any>
? RuntimeValue<Overrideable<T[K], `${Path}_${UpperSnakeCase<K>}`>, `You can override this value at runtime with NUXT${Path}_${UpperSnakeCase<K>}`>
: RuntimeValue<T[K], `You can override this value at runtime with NUXT${Path}_${UpperSnakeCase<K>}`>
: never
}
/** User configuration in `nuxt.config` file */
export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite'>> {
export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite' | 'runtimeConfig'>> {
// Avoid DeepPartial for vite config interface (#4772)
vite?: ConfigSchema['vite']
runtimeConfig?: Overrideable<RuntimeConfig>
/**
* Experimental custom config schema

View File

@ -49,6 +49,8 @@ export default defineNuxtConfig({
}
},
runtimeConfig: {
baseURL: '',
baseAPIToken: '',
privateConfig: 'secret_key',
public: {
needsFallback: undefined,

View File

@ -1,7 +1,7 @@
import { expectTypeOf } from 'expect-type'
import { describe, it } from 'vitest'
import type { Ref } from 'vue'
import type { AppConfig } from '@nuxt/schema'
import type { AppConfig, RuntimeValue } from '@nuxt/schema'
import type { FetchError } from 'ofetch'
import type { NavigationFailure, RouteLocationNormalizedLoaded, RouteLocationRaw, useRouter as vueUseRouter } from 'vue-router'
@ -124,9 +124,25 @@ describe('runtimeConfig', () => {
it('generated runtimeConfig types', () => {
const runtimeConfig = useRuntimeConfig()
expectTypeOf(runtimeConfig.public.testConfig).toEqualTypeOf<number>()
expectTypeOf(runtimeConfig.public.needsFallback).toEqualTypeOf<string>()
expectTypeOf(runtimeConfig.privateConfig).toEqualTypeOf<string>()
expectTypeOf(runtimeConfig.unknown).toEqualTypeOf<any>()
})
it('provides hints on overriding these values', () => {
const val = defineNuxtConfig({
runtimeConfig: {
public: {
// @ts-expect-error
testConfig: 'test'
}
}
})
expectTypeOf(val.runtimeConfig!.public!.testConfig).toEqualTypeOf<undefined | RuntimeValue<number, 'You can override this value at runtime with NUXT_PUBLIC_TEST_CONFIG'>>()
expectTypeOf(val.runtimeConfig!.privateConfig).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_PRIVATE_CONFIG'>>()
expectTypeOf(val.runtimeConfig!.baseURL).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_BASE_URL'>>()
expectTypeOf(val.runtimeConfig!.baseAPIToken).toEqualTypeOf<undefined | RuntimeValue<string, 'You can override this value at runtime with NUXT_BASE_API_TOKEN'>>()
expectTypeOf(val.runtimeConfig!.unknown).toEqualTypeOf<any>()
})
})
describe('head', () => {