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

TS: Enable strict mode #3143

Merged
merged 9 commits into from May 27, 2021
Merged
2 changes: 1 addition & 1 deletion src/__tests__/starWarsSchema.ts
Expand Up @@ -98,7 +98,7 @@ const episodeEnum = new GraphQLEnumType({
* secretBackstory: String
* }
*/
const characterInterface = new GraphQLInterfaceType({
const characterInterface: GraphQLInterfaceType = new GraphQLInterfaceType({
name: 'Character',
description: 'A character in the Star Wars Trilogy',
fields: () => ({
Expand Down
9 changes: 0 additions & 9 deletions src/error/GraphQLError.ts
Expand Up @@ -14,15 +14,6 @@ import { printLocation, printSourceLocation } from '../language/printLocation';
* GraphQL document and/or execution result that correspond to the Error.
*/
export class GraphQLError extends Error {
/**
* A message describing the Error for debugging purposes.
*
* Enumerable, and appears in the result of JSON.stringify().
*
* Note: should be treated as readonly, despite invariant usage.
*/
message: string;

/**
* An array of { line, column } locations within the source GraphQL document
* which correspond to this error.
Expand Down
2 changes: 2 additions & 0 deletions src/error/__tests__/formatError-test.ts
Expand Up @@ -45,10 +45,12 @@ describe('formatError: default error formatter', () => {
});

it('rejects null and undefined errors', () => {
// @ts-expect-error (formatError expects a value)
expect(() => formatError(undefined)).to.throw(
'Received null or undefined error.',
);

// @ts-expect-error (formatError expects a value)
expect(() => formatError(null)).to.throw(
'Received null or undefined error.',
);
Expand Down
17 changes: 8 additions & 9 deletions src/error/locatedError.ts
Expand Up @@ -22,21 +22,20 @@ export function locatedError(
: new Error('Unexpected error value: ' + inspect(rawOriginalError));

// Note: this uses a brand-check to support GraphQL errors originating from other contexts.
// @ts-expect-error FIXME: TS Conversion
if (Array.isArray(originalError.path)) {
// @ts-expect-error
if (isLocatedGraphQLError(originalError)) {
return originalError;
}

return new GraphQLError(
originalError.message,
// @ts-expect-error FIXME
originalError.nodes ?? nodes,
// @ts-expect-error FIXME
originalError.source,
// @ts-expect-error FIXME
originalError.positions,
(originalError as GraphQLError).nodes ?? nodes,
(originalError as GraphQLError).source,
(originalError as GraphQLError).positions,
path,
originalError,
);
}

function isLocatedGraphQLError(error: any): error is GraphQLError {
return Array.isArray(error.path);
}
6 changes: 3 additions & 3 deletions src/execution/__tests__/abstract-test.ts
Expand Up @@ -577,9 +577,9 @@ describe('Execute: Handles execution of abstract types', () => {
);

// FIXME: workaround since we can't inject resolveType into SDL
assertInterfaceType(schema.getType('Pet')).resolveType =
// @ts-expect-error
() => schema.getType('Cat');
// @ts-expect-error
assertInterfaceType(schema.getType('Pet')).resolveType = () =>
schema.getType('Cat');
expectError({ forTypeName: undefined }).toEqual(
'Support for returning GraphQLObjectType from resolveType was removed in graphql-js@16.0.0 please return type name instead.',
);
Expand Down
6 changes: 3 additions & 3 deletions src/execution/__tests__/executor-test.ts
Expand Up @@ -94,7 +94,7 @@ describe('Execute: Handles basic execution tasks', () => {
return Promise.resolve(data);
}

const DataType = new GraphQLObjectType({
const DataType: GraphQLObjectType = new GraphQLObjectType({
name: 'DataType',
fields: () => ({
a: { type: GraphQLString },
Expand Down Expand Up @@ -185,7 +185,7 @@ describe('Execute: Handles basic execution tasks', () => {
});

it('merges parallel fragments', () => {
const Type = new GraphQLObjectType({
const Type: GraphQLObjectType = new GraphQLObjectType({
name: 'Type',
fields: () => ({
a: { type: GraphQLString, resolve: () => 'Apple' },
Expand Down Expand Up @@ -624,7 +624,7 @@ describe('Execute: Handles basic execution tasks', () => {
});

it('Full response path is included for non-nullable fields', () => {
const A = new GraphQLObjectType({
const A: GraphQLObjectType = new GraphQLObjectType({
name: 'A',
fields: () => ({
nullableA: {
Expand Down
2 changes: 1 addition & 1 deletion src/execution/__tests__/schema-test.ts
Expand Up @@ -29,7 +29,7 @@ describe('Execute: Handles execution with a complex schema', () => {
},
});

const BlogAuthor = new GraphQLObjectType({
const BlogAuthor: GraphQLObjectType = new GraphQLObjectType({
name: 'Author',
fields: () => ({
id: { type: GraphQLString },
Expand Down
14 changes: 7 additions & 7 deletions src/execution/__tests__/union-interface-test.ts
Expand Up @@ -65,14 +65,14 @@ const NamedType = new GraphQLInterfaceType({
},
});

const LifeType = new GraphQLInterfaceType({
const LifeType: GraphQLInterfaceType = new GraphQLInterfaceType({
name: 'Life',
fields: () => ({
progeny: { type: new GraphQLList(LifeType) },
}),
});

const MammalType = new GraphQLInterfaceType({
const MammalType: GraphQLInterfaceType = new GraphQLInterfaceType({
name: 'Mammal',
interfaces: [LifeType],
fields: () => ({
Expand All @@ -82,7 +82,7 @@ const MammalType = new GraphQLInterfaceType({
}),
});

const DogType = new GraphQLObjectType({
const DogType: GraphQLObjectType = new GraphQLObjectType({
name: 'Dog',
interfaces: [MammalType, LifeType, NamedType],
fields: () => ({
Expand All @@ -95,7 +95,7 @@ const DogType = new GraphQLObjectType({
isTypeOf: (value) => value instanceof Dog,
});

const CatType = new GraphQLObjectType({
const CatType: GraphQLObjectType = new GraphQLObjectType({
name: 'Cat',
interfaces: [MammalType, LifeType, NamedType],
fields: () => ({
Expand Down Expand Up @@ -125,7 +125,7 @@ const PetType = new GraphQLUnionType({
},
});

const PersonType = new GraphQLObjectType({
const PersonType: GraphQLObjectType = new GraphQLObjectType({
name: 'Person',
interfaces: [NamedType, MammalType, LifeType],
fields: () => ({
Expand Down Expand Up @@ -503,7 +503,7 @@ describe('Execute: Union and intersection types', () => {
let encounteredSchema;
let encounteredRootValue;

const NamedType2 = new GraphQLInterfaceType({
const NamedType2: GraphQLInterfaceType = new GraphQLInterfaceType({
name: 'Named',
fields: {
name: { type: GraphQLString },
Expand All @@ -516,7 +516,7 @@ describe('Execute: Union and intersection types', () => {
},
});

const PersonType2 = new GraphQLObjectType({
const PersonType2: GraphQLObjectType = new GraphQLObjectType({
name: 'Person',
interfaces: [NamedType2],
fields: {
Expand Down
9 changes: 7 additions & 2 deletions src/execution/__tests__/variables-test.ts
Expand Up @@ -7,7 +7,10 @@ import { invariant } from '../../jsutils/invariant';
import { Kind } from '../../language/kinds';
import { parse } from '../../language/parser';

import type { GraphQLArgumentConfig } from '../../type/definition';
import type {
GraphQLFieldConfig,
GraphQLArgumentConfig,
} from '../../type/definition';
import { GraphQLSchema } from '../../type/schema';
import { GraphQLString } from '../../type/scalars';
import {
Expand Down Expand Up @@ -64,7 +67,9 @@ const TestEnum = new GraphQLEnumType({
},
});

function fieldWithInputArg(inputArg: GraphQLArgumentConfig) {
function fieldWithInputArg(
inputArg: GraphQLArgumentConfig,
): GraphQLFieldConfig<any, any> {
return {
type: GraphQLString,
args: { input: inputArg },
Expand Down
4 changes: 1 addition & 3 deletions src/execution/execute.ts
Expand Up @@ -180,7 +180,7 @@ export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
);

// Return early errors if execution context failed.
if (Array.isArray(exeContext)) {
if (!('schema' in exeContext)) {
return { errors: exeContext };
}

Expand All @@ -191,9 +191,7 @@ export function execute(args: ExecutionArgs): PromiseOrValue<ExecutionResult> {
// field and its descendants will be omitted, and sibling fields will still
// be executed. An execution which encounters errors will still result in a
// resolved Promise.
// @ts-expect-error FIXME: TS Conversion
const data = executeOperation(exeContext, exeContext.operation, rootValue);
// @ts-expect-error FIXME: TS Conversion
return buildResponse(exeContext, data);
}

Expand Down
4 changes: 2 additions & 2 deletions src/execution/values.ts
Expand Up @@ -77,7 +77,7 @@ function coerceVariableValues(
inputs: { readonly [variable: string]: unknown },
onError: (error: GraphQLError) => void,
): { [variable: string]: unknown } {
const coercedValues = {};
const coercedValues: { [variable: string]: unknown } = {};
for (const varDefNode of varDefNodes) {
const varName = varDefNode.variable.name.value;
const varType = typeFromAST(schema, varDefNode.type);
Expand Down Expand Up @@ -162,7 +162,7 @@ export function getArgumentValues(
node: FieldNode | DirectiveNode,
variableValues?: Maybe<ObjMap<unknown>>,
): { [argument: string]: unknown } {
const coercedValues = {};
const coercedValues: { [argument: string]: unknown } = {};

// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const argumentNodes = node.arguments ?? [];
Expand Down
2 changes: 1 addition & 1 deletion src/jsutils/__tests__/identityFunc-test.ts
Expand Up @@ -5,7 +5,7 @@ import { identityFunc } from '../identityFunc';

describe('identityFunc', () => {
it('returns the first argument it receives', () => {
// @ts-expect-error FIXME: TS Conversion
// @ts-expect-error (Expects an argument)
expect(identityFunc()).to.equal(undefined);
expect(identityFunc(undefined)).to.equal(undefined);
expect(identityFunc(null)).to.equal(null);
Expand Down
21 changes: 14 additions & 7 deletions src/jsutils/__tests__/inspect-test.ts
Expand Up @@ -132,13 +132,13 @@ describe('inspect', () => {
'{ self: [Circular], deepSelf: { self: [Circular] } }',
);

const array = [];
const array: any = [];
array[0] = array;
array[1] = [array];

expect(inspect(array)).to.equal('[[Circular], [[Circular]]]');

const mixed = { array: [] };
const mixed: any = { array: [] };
mixed.array[0] = mixed;

expect(inspect(mixed)).to.equal('{ array: [[Circular]] }');
Expand All @@ -165,14 +165,21 @@ describe('inspect', () => {

expect(inspect([[new Foo()]])).to.equal('[[[Foo]]]');

Foo.prototype[Symbol.toStringTag] = 'Bar';
expect(inspect([[new Foo()]])).to.equal('[[[Bar]]]');
class Foo2 {
foo: string;

[Symbol.toStringTag] = 'Bar';

constructor() {
this.foo = 'bar';
}
}
expect(inspect([[new Foo2()]])).to.equal('[[[Bar]]]');

// eslint-disable-next-line func-names
const objectWithoutClassName = new (function () {
// eslint-disable-next-line @typescript-eslint/no-invalid-this
const objectWithoutClassName = new (function (this: any) {
this.foo = 1;
})();
} as any)();
expect(inspect([[objectWithoutClassName]])).to.equal('[[[Object]]]');
});
});
7 changes: 3 additions & 4 deletions src/jsutils/didYouMean.ts
Expand Up @@ -12,10 +12,9 @@ export function didYouMean(
firstArg: string | ReadonlyArray<string>,
secondArg?: ReadonlyArray<string>,
) {
const [subMessage, suggestionsArg] =
typeof firstArg === 'string'
? [firstArg, secondArg]
: [undefined, firstArg];
const [subMessage, suggestionsArg] = secondArg
? [firstArg as string, secondArg]
: [undefined, firstArg as ReadonlyArray<string>];

let message = ' Did you mean ';
if (subMessage) {
Expand Down
16 changes: 9 additions & 7 deletions src/jsutils/inspect.ts
Expand Up @@ -22,7 +22,7 @@ function formatValue(value: unknown, seenValues: Array<unknown>): string {
}

function formatObjectValue(
value: Object,
value: object | null,
previouslySeenValues: Array<unknown>,
): string {
if (value === null) {
Expand All @@ -35,10 +35,8 @@ function formatObjectValue(

const seenValues = [...previouslySeenValues, value];

// @ts-expect-error FIXME: TS Conversion
if (typeof value.toJSON === 'function') {
// @ts-expect-error FIXME: TS Conversion
const jsonValue = (value.toJSON as () => unknown)();
if (isJSONable(value)) {
const jsonValue = value.toJSON();

// check for infinite recursion
if (jsonValue !== value) {
Expand All @@ -53,7 +51,11 @@ function formatObjectValue(
return formatObject(value, seenValues);
}

function formatObject(object: Object, seenValues: Array<unknown>): string {
function isJSONable(value: any): value is { toJSON: () => unknown } {
return typeof value.toJSON === 'function';
}

function formatObject(object: object, seenValues: Array<unknown>): string {
const entries = Object.entries(object);
if (entries.length === 0) {
return '{}';
Expand Down Expand Up @@ -98,7 +100,7 @@ function formatArray(
return '[' + items.join(', ') + ']';
}

function getObjectTag(object: Object): string {
function getObjectTag(object: object): string {
const tag = Object.prototype.toString
.call(object)
.replace(/^\[object /, '')
Expand Down
2 changes: 1 addition & 1 deletion src/jsutils/isAsyncIterable.ts
Expand Up @@ -3,7 +3,7 @@
* implementing a `Symbol.asyncIterator` method.
*/
export function isAsyncIterable(
maybeAsyncIterable: unknown,
maybeAsyncIterable: any,
): maybeAsyncIterable is AsyncIterable<unknown> {
return typeof maybeAsyncIterable?.[Symbol.asyncIterator] === 'function';
}
2 changes: 1 addition & 1 deletion src/jsutils/isIterableObject.ts
Expand Up @@ -15,7 +15,7 @@
* isIterableObject({ length: 1, 0: 'Alpha' }) // false
*/
export function isIterableObject(
maybeIterable: unknown,
maybeIterable: any,
): maybeIterable is Iterable<unknown> {
return (
typeof maybeIterable === 'object' &&
Expand Down
5 changes: 2 additions & 3 deletions src/jsutils/isPromise.ts
Expand Up @@ -2,7 +2,6 @@
* Returns true if the value acts like a Promise, i.e. has a "then" function,
* otherwise returns false.
*/
export function isPromise(value: unknown): value is Promise<unknown> {
// eslint-disable-next-line @typescript-eslint/dot-notation
return typeof value?.['then'] === 'function';
export function isPromise(value: any): value is Promise<unknown> {
return typeof value?.then === 'function';
}
2 changes: 1 addition & 1 deletion src/jsutils/memoize3.ts
Expand Up @@ -7,7 +7,7 @@ export function memoize3<
A3 extends object,
R,
>(fn: (a1: A1, a2: A2, a3: A3) => R): (a1: A1, a2: A2, a3: A3) => R {
let cache0;
let cache0: WeakMap<A1, WeakMap<A2, WeakMap<A3, R>>>;

return function memoized(a1, a2, a3) {
if (cache0 === undefined) {
Expand Down