Skip to content

Commit

Permalink
fix(scripts): infer types from use()
Browse files Browse the repository at this point in the history
  • Loading branch information
harlan-zw committed Aug 20, 2024
1 parent 3fe9217 commit 7746a35
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 7 deletions.
8 changes: 7 additions & 1 deletion examples/vite-ssr-vue/src/pages/gtag.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<script setup lang="ts">
import { useScript } from '@unhead/vue'
const gtag = useScript<{ dataLayer: any[] }>({
declare global {
interface Window {
dataLayer: any[]
}
}
const gtag = useScript({
src: 'https://www.googletagmanager.com/gtm.js?id=GTM-MNJD4B',
}, {
beforeInit() {
Expand Down
10 changes: 6 additions & 4 deletions packages/schema/src/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ type BaseScriptApi = Record<symbol | string, any>

export type AsAsyncFunctionValues<T extends BaseScriptApi> = {
[key in keyof T]:
// arays return literals
T[key] extends any[] ? T[key] :
T[key] extends object ? AsAsyncFunctionValues<T[key]> :
T[key] extends (...args: infer A) => infer R ? (...args: A) => Promise<R> : () => Promise<T[key]>
T[key] extends (...args: infer A) => infer R ? (...args: A) => R :
T[key] extends Record<any, any> ? AsAsyncFunctionValues<T[key]> :
never
}

export interface ScriptInstance<T extends BaseScriptApi> {
Expand All @@ -38,7 +38,9 @@ export interface ScriptInstance<T extends BaseScriptApi> {
}
}

export interface UseScriptOptions<T extends BaseScriptApi> extends HeadEntryOptions {
export type UseFunctionType<T, U> = T extends { use: infer V } ? V extends () => infer W ? W : U : U

export interface UseScriptOptions<T extends BaseScriptApi = {}, U = {}> extends HeadEntryOptions {
/**
* Resolve the script instance from the window.
*/
Expand Down
4 changes: 3 additions & 1 deletion packages/unhead/src/composables/useScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import type {
AsAsyncFunctionValues,
Head,
ScriptInstance,
UseFunctionType,
UseScriptInput,
UseScriptOptions,
UseScriptResolvedInput,
} from '@unhead/schema'

import { getActiveHead } from './useActiveHead'

export type UseScriptContext<T extends Record<symbol | string, any>> =
Expand All @@ -32,7 +34,7 @@ export function resolveScriptKey(input: UseScriptResolvedInput) {
*
* @see https://unhead.unjs.io/usage/composables/use-script
*/
export function useScript<T extends Record<symbol | string, any>>(_input: UseScriptInput, _options?: UseScriptOptions<T>): UseScriptContext<T> {
export function useScript<T extends Record<symbol | string, any> = Record<symbol | string, any>, U = Record<symbol | string, any>>(_input: UseScriptInput, _options?: UseScriptOptions<T, U>): UseScriptContext<UseFunctionType<UseScriptOptions<T, U>, T>> {
const input: UseScriptResolvedInput = typeof _input === 'string' ? { src: _input } : _input
const options = _options || {}
const head = options.head || getActiveHead()
Expand Down
4 changes: 3 additions & 1 deletion packages/vue/src/composables/useScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import type {
SchemaAugmentations,
ScriptBase,
ScriptInstance,
UseFunctionType,
UseScriptOptions,
UseScriptResolvedInput,
UseScriptStatus,
} from '@unhead/schema'
import { useScript as _useScript, resolveScriptKey } from 'unhead'
import type { Ref } from 'vue'
import { getCurrentInstance, onMounted, onScopeDispose, ref } from 'vue'

import type { MaybeComputedRefEntriesOnly } from '../types'
import { injectHead } from './injectHead'

Expand All @@ -31,7 +33,7 @@ export type UseScriptContext<T extends Record<symbol | string, any>> =
$script: Promise<T> & VueScriptInstance<T>
}

export function useScript<T extends Record<symbol | string, any>>(_input: UseScriptInput, _options?: UseScriptOptions<T>): UseScriptContext<T> {
export function useScript<T extends Record<symbol | string, any> = Record<symbol | string, any>, U = Record<symbol | string, any>>(_input: UseScriptInput, _options?: UseScriptOptions<T, U>): UseScriptContext<UseFunctionType<UseScriptOptions<T, U>, T>> {
const input = (typeof _input === 'string' ? { src: _input } : _input) as UseScriptResolvedInput
const head = injectHead()
const options = _options || {}
Expand Down

0 comments on commit 7746a35

Please sign in to comment.