Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Declarations can't be emitted when types from inner modules are exported through separate export declarations #56856

Closed
Andarist opened this issue Dec 23, 2023 · 0 comments Β· Fixed by #56857
Assignees
Labels
Fix Available A PR has been opened for this issue Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Milestone

Comments

@Andarist
Copy link
Contributor

πŸ”Ž Search Terms

declarations portable emit modules export declaration alias aliasing

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

N/A

πŸ’» Code

// @strict: true
// @declaration: true
// @module: nodenext
// @moduleResolution: nodenext
// @target: esnext

// @filename: node_modules/@tanstack/vue-query/build/modern/useQuery-CPqkvEsh.d.ts
type QueryKey = ReadonlyArray<unknown>;

interface Register {}

type DefaultError = Register extends {
  defaultError: infer TError;
}
  ? TError
  : Error;

type ShouldRetryFunction<TError = DefaultError> = (
  failureCount: number,
  error: TError,
) => boolean;
type RetryValue<TError> = boolean | number | ShouldRetryFunction<TError>;

type QueryFunctionContext<
  TQueryKey extends QueryKey = QueryKey,
  TPageParam = never,
> = [TPageParam] extends [never]
  ? {
      queryKey: TQueryKey;
    }
  : {
      queryKey: TQueryKey;
      pageParam: TPageParam;
    };

type QueryFunction<
  T = unknown,
  TQueryKey extends QueryKey = QueryKey,
  TPageParam = never,
> = (context: QueryFunctionContext<TQueryKey, TPageParam>) => T | Promise<T>;

interface QueryOptions<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
  TPageParam = never,
> {
  retry?: RetryValue<TError>;
  queryFn?: QueryFunction<TQueryFnData, TQueryKey, TPageParam>;
  queryKey?: TQueryKey;
  initialData?: TData;
  initialDataUpdatedAt?: number | (() => number | undefined);
}

interface QueryObserverOptions<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
  TPageParam = never,
> extends QueryOptions<
    TQueryFnData,
    TError,
    TQueryData,
    TQueryKey,
    TPageParam
  > {
  enabled?: boolean;
  refetchInterval?: number;
  select?: (data: TQueryData) => TData;
}

type UseQueryOptions<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
> = {
  [Property in keyof QueryObserverOptions<
    TQueryFnData,
    TError,
    TData,
    TQueryData,
    TQueryKey
  >]: QueryObserverOptions<
    TQueryFnData,
    TError,
    TData,
    TQueryData,
    TQueryKey
  >[Property];
};

type UndefinedInitialQueryOptions<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
> = UseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey> & {
  initialData?: undefined;
};

interface QueryObserverBaseResult<TData = unknown, TError = DefaultError> {
  data: TData | undefined;
  dataUpdatedAt: number;
  error: TError | null;
  errorUpdatedAt: number;
  failureCount: number;
  failureReason: TError | null;
  errorUpdateCount: number;
  isError: boolean;
  isFetched: boolean;
  isFetchedAfterMount: boolean;
  isFetching: boolean;
  isLoading: boolean;
  isPending: boolean;
  isLoadingError: boolean;
  isInitialLoading: boolean;
  isPaused: boolean;
  isPlaceholderData: boolean;
  isRefetchError: boolean;
  isRefetching: boolean;
  isStale: boolean;
  isSuccess: boolean;
}

interface QueryObserverSuccessResult<TData = unknown, TError = DefaultError>
  extends QueryObserverBaseResult<TData, TError> {
  data: TData;
  error: null;
  isError: false;
  isPending: false;
  isLoadingError: false;
  isRefetchError: false;
  isSuccess: true;
  status: "success";
}

type DefinedQueryObserverResult<
  TData = unknown,
  TError = DefaultError,
> = QueryObserverSuccessResult<TData, TError>;
type QueryObserverResult<
  TData = unknown,
  TError = DefaultError,
> = DefinedQueryObserverResult<TData, TError>;

type ToRef<T> = {
  value: T;
};

type UseBaseQueryReturnType<
  TData,
  TError,
  Result = QueryObserverResult<TData, TError>,
> = {
  [K in keyof Result]: K extends
    | "fetchNextPage"
    | "fetchPreviousPage"
    | "refetch"
    ? Result[K]
    : ToRef<Readonly<Result>[K]>;
} & {
  suspense: () => Promise<Result>;
};

type UseQueryReturnType<TData, TError> = UseBaseQueryReturnType<TData, TError>;

declare function useQuery<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
>(
  options: UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
): UseQueryReturnType<TData, TError>;

export { type UseQueryReturnType as b, useQuery as u };

// @filename: node_modules/@tanstack/vue-query/build/modern/index.d.ts
export { b as UseQueryReturnType, u as useQuery } from './useQuery-CPqkvEsh.js';

// @filename: node_modules/@tanstack/vue-query/package.json
{
  "name": "@tanstack/vue-query",
  "type": "module",
  "exports": {
    ".": {
      "import": {
        "types": "./build/modern/index.d.ts",
        "default": "./build/modern/index.js"
      },
      "require": {
        "types": "./build/modern/index.d.cts",
        "default": "./build/modern/index.cjs"
      }
    }
  }
}

// @filename: src/index.mts
import { useQuery } from '@tanstack/vue-query'

const baseUrl = 'https://api.publicapis.org/'

interface IEntry {
  API: string
  Description: string
  Auth: string
  HTTPS: boolean
  Cors: string
  Link: string
  Category: string
}

const testApi = {
  getEntries: (): Promise<IEntry[]> => {
    return fetch(baseUrl + 'entries')
      .then((res) => res.json())
      .then((data) => data.entries)
      .catch((err) => console.log(err))
  }
}

const entryKeys = {
  all: ['entries'] as const,
  list: () => [...entryKeys.all, 'list'] as const
}

export const useEntries = () => {
  return useQuery({
    queryKey: entryKeys.list(),
    queryFn: testApi.getEntries,
    select: (data) => data.slice(0, 10)
  })
}

πŸ™ Actual behavior

The inferred type of 'useEntries' cannot be named without a reference to '../../node_modules/@tanstack/vue-query/build/modern/useQuery-d58edace'. This is likely not portable. A type annotation is necessary.ts(2742)

πŸ™‚ Expected behavior

A declaration like this should be emitted successfully:

interface IEntry {
    API: string;
    Description: string;
    Auth: string;
    HTTPS: boolean;
    Cors: string;
    Link: string;
    Category: string;
}
export declare const useEntries: () => import("@tanstack/vue-query").UseQueryReturnType<IEntry[], Error>;
export {};

Additional information about the issue

It originally has been reported here: TanStack/query#6318

@RyanCavanaugh RyanCavanaugh added the Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases label Jan 2, 2024
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Jan 2, 2024
@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Jan 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fix Available A PR has been opened for this issue Possible Improvement The current behavior isn't wrong, but it's possible to see that it might be better in some cases
Projects
None yet
4 participants