├── .gitignore ├── prisma ├── dev.db ├── dev.db-journal ├── migrations │ ├── migration_lock.toml │ ├── 20210919082039_init │ │ └── migration.sql │ ├── 20210919132143_add_vote_model │ │ └── migration.sql │ └── 20210919091710_add_user_model │ │ └── migration.sql └── schema.prisma ├── README.md ├── src ├── pubsub.ts ├── script.ts ├── context.ts ├── auth.ts ├── schema.graphql ├── index.ts └── schema.ts ├── package.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | # Keep environment variables out of version control 3 | .env 4 | -------------------------------------------------------------------------------- /prisma/dev.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howtographql/typescript-helix/HEAD/prisma/dev.db -------------------------------------------------------------------------------- /prisma/dev.db-journal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howtographql/typescript-helix/HEAD/prisma/dev.db-journal -------------------------------------------------------------------------------- /prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "sqlite" -------------------------------------------------------------------------------- /prisma/migrations/20210919082039_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "Link" ( 3 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 4 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 5 | "description" TEXT NOT NULL, 6 | "url" TEXT NOT NULL 7 | ); 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository holds the code for the [HowToGraphQL tutorial with Typescript, Helix and Prisma](https://www.howtographql.com/typescript-helix/0-introduction/). 2 | 3 | Written and maintained by https://github.com/howtographql and [The Guild](https://the-guild.dev/) members: https://github.com/dotansimha, https://github.com/urigo and https://github.com/saihaj. 4 | -------------------------------------------------------------------------------- /src/pubsub.ts: -------------------------------------------------------------------------------- 1 | import { Link, Vote } from "@prisma/client"; 2 | import { PubSub } from "graphql-subscriptions"; 3 | import { TypedPubSub } from "typed-graphql-subscriptions"; 4 | 5 | export type PubSubChannels = { 6 | newLink: [{ createdLink: Link }]; 7 | newVote: [{ createdVote: Vote }]; 8 | }; 9 | 10 | export const pubSub = new TypedPubSub(new PubSub()); 11 | -------------------------------------------------------------------------------- /src/script.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from "@prisma/client"; 2 | 3 | const prisma = new PrismaClient(); 4 | 5 | async function main() { 6 | const newLink = await prisma.link.create({ 7 | data: { 8 | description: "Fullstack tutorial for GraphQL", 9 | url: "www.howtographql.com", 10 | }, 11 | }); 12 | const allLinks = await prisma.link.findMany(); 13 | 14 | console.log(allLinks); 15 | } 16 | 17 | main() 18 | .catch((e) => { 19 | throw e; 20 | }) 21 | .finally(async () => { 22 | await prisma.$disconnect(); 23 | }); 24 | -------------------------------------------------------------------------------- /prisma/migrations/20210919132143_add_vote_model/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "Vote" ( 3 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 4 | "linkId" INTEGER NOT NULL, 5 | "userId" INTEGER NOT NULL, 6 | CONSTRAINT "Vote_linkId_fkey" FOREIGN KEY ("linkId") REFERENCES "Link" ("id") ON DELETE RESTRICT ON UPDATE CASCADE, 7 | CONSTRAINT "Vote_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE 8 | ); 9 | 10 | -- CreateIndex 11 | CREATE UNIQUE INDEX "Vote_linkId_userId_key" ON "Vote"("linkId", "userId"); 12 | -------------------------------------------------------------------------------- /src/context.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient, User } from "@prisma/client"; 2 | import { FastifyRequest } from "fastify"; 3 | import { authenticateUser } from "./auth"; 4 | import { pubSub } from "./pubsub"; 5 | 6 | const prisma = new PrismaClient(); 7 | 8 | export type GraphQLContext = { 9 | prisma: PrismaClient; 10 | currentUser: User | null; 11 | pubSub: typeof pubSub; 12 | }; 13 | 14 | export async function contextFactory( 15 | request: FastifyRequest 16 | ): Promise { 17 | return { 18 | prisma, 19 | currentUser: await authenticateUser(prisma, request), 20 | pubSub, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/auth.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient, User } from "@prisma/client"; 2 | import { FastifyRequest } from "fastify"; 3 | import { JwtPayload, verify } from "jsonwebtoken"; 4 | 5 | export const APP_SECRET = "this is my secret"; 6 | 7 | export async function authenticateUser( 8 | prisma: PrismaClient, 9 | request: FastifyRequest 10 | ): Promise { 11 | if (request.headers.authorization) { 12 | const token = request.headers.authorization.split(" ")[1]; 13 | const tokenPayload = verify(token, APP_SECRET) as JwtPayload; 14 | const userId = tokenPayload.userId; 15 | 16 | return await prisma.user.findUnique({ where: { id: userId } }); 17 | } 18 | 19 | return null; 20 | } 21 | -------------------------------------------------------------------------------- /prisma/migrations/20210919091710_add_user_model/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "User" ( 3 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 4 | "name" TEXT NOT NULL, 5 | "email" TEXT NOT NULL, 6 | "password" TEXT NOT NULL 7 | ); 8 | 9 | -- RedefineTables 10 | PRAGMA foreign_keys=OFF; 11 | CREATE TABLE "new_Link" ( 12 | "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 13 | "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, 14 | "description" TEXT NOT NULL, 15 | "url" TEXT NOT NULL, 16 | "postedById" INTEGER, 17 | CONSTRAINT "Link_postedById_fkey" FOREIGN KEY ("postedById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE 18 | ); 19 | INSERT INTO "new_Link" ("createdAt", "description", "id", "url") SELECT "createdAt", "description", "id", "url" FROM "Link"; 20 | DROP TABLE "Link"; 21 | ALTER TABLE "new_Link" RENAME TO "Link"; 22 | PRAGMA foreign_key_check; 23 | PRAGMA foreign_keys=ON; 24 | 25 | -- CreateIndex 26 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); 27 | -------------------------------------------------------------------------------- /prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | datasource db { 5 | provider = "sqlite" 6 | url = "file:./dev.db" 7 | } 8 | 9 | generator client { 10 | provider = "prisma-client-js" 11 | } 12 | 13 | model Link { 14 | id Int @id @default(autoincrement()) 15 | createdAt DateTime @default(now()) 16 | description String 17 | url String 18 | postedBy User? @relation(fields: [postedById], references: [id]) 19 | postedById Int? 20 | votes Vote[] 21 | } 22 | 23 | model User { 24 | id Int @id @default(autoincrement()) 25 | name String 26 | email String @unique 27 | password String 28 | links Link[] 29 | votes Vote[] 30 | } 31 | 32 | model Vote { 33 | id Int @id @default(autoincrement()) 34 | link Link @relation(fields: [linkId], references: [id]) 35 | linkId Int 36 | user User @relation(fields: [userId], references: [id]) 37 | userId Int 38 | 39 | @@unique([linkId, userId]) 40 | } -------------------------------------------------------------------------------- /src/schema.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | info: String! 3 | feed(filter: String, skip: Int, take: Int, orderBy: LinkOrderByInput): Feed! 4 | me: User! 5 | } 6 | 7 | type Feed { 8 | links: [Link!]! 9 | count: Int! 10 | } 11 | 12 | type Mutation { 13 | post(url: String!, description: String!): Link! 14 | signup(email: String!, password: String!, name: String!): AuthPayload 15 | login(email: String!, password: String!): AuthPayload 16 | vote(linkId: ID!): Vote 17 | } 18 | 19 | type Vote { 20 | id: ID! 21 | link: Link! 22 | user: User! 23 | } 24 | 25 | type Link { 26 | id: ID! 27 | description: String! 28 | url: String! 29 | postedBy: User 30 | votes: [Vote!]! 31 | } 32 | 33 | type AuthPayload { 34 | token: String 35 | user: User 36 | } 37 | 38 | type User { 39 | id: ID! 40 | name: String! 41 | email: String! 42 | links: [Link!]! 43 | } 44 | 45 | type Subscription { 46 | newLink: Link 47 | newVote: Vote 48 | } 49 | 50 | input LinkOrderByInput { 51 | description: Sort 52 | url: Sort 53 | createdAt: Sort 54 | } 55 | 56 | enum Sort { 57 | asc 58 | desc 59 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "howtogql-ts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "ts-node-dev --exit-child src/index.ts", 8 | "start": "ts-node src/index.ts" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/dotansimha/graphql-typescript-node-tutorial.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/dotansimha/graphql-typescript-node-tutorial/issues" 19 | }, 20 | "homepage": "https://github.com/dotansimha/graphql-typescript-node-tutorial#readme", 21 | "devDependencies": { 22 | "@prisma/client": "^3.0.2", 23 | "@types/bcryptjs": "^2.4.2", 24 | "@types/jsonwebtoken": "^8.5.5", 25 | "@types/node": "^16.9.2", 26 | "prisma": "^3.0.2", 27 | "ts-node": "^10.2.1", 28 | "ts-node-dev": "^1.1.8", 29 | "typescript": "^4.4.3" 30 | }, 31 | "dependencies": { 32 | "@graphql-tools/schema": "^8.2.0", 33 | "bcryptjs": "^2.4.3", 34 | "fastify": "^3.21.3", 35 | "graphql": "^15.5.3", 36 | "graphql-import-node": "^0.0.4", 37 | "graphql-helix": "^1.8.2", 38 | "graphql-subscriptions": "^1.2.1", 39 | "jsonwebtoken": "^8.5.1", 40 | "typed-graphql-subscriptions": "^0.0.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import "graphql-import-node"; 2 | import fastify from "fastify"; 3 | import { 4 | getGraphQLParameters, 5 | processRequest, 6 | Request, 7 | sendResult, 8 | shouldRenderGraphiQL, 9 | renderGraphiQL, 10 | } from "graphql-helix"; 11 | import { schema } from "./schema"; 12 | import { contextFactory } from "./context"; 13 | 14 | async function main() { 15 | const server = fastify(); 16 | 17 | server.route({ 18 | method: ["POST", "GET"], 19 | url: "/graphql", 20 | handler: async (req, reply) => { 21 | const request: Request = { 22 | headers: req.headers, 23 | method: req.method, 24 | query: req.query, 25 | body: req.body, 26 | }; 27 | 28 | if (shouldRenderGraphiQL(request)) { 29 | reply.header("Content-Type", "text/html"); 30 | reply.send( 31 | renderGraphiQL({ 32 | endpoint: "/graphql", 33 | }) 34 | ); 35 | 36 | return; 37 | } 38 | 39 | const { operationName, query, variables } = getGraphQLParameters(request); 40 | 41 | const result = await processRequest({ 42 | request, 43 | schema, 44 | operationName, 45 | contextFactory: () => contextFactory(req), 46 | query, 47 | variables, 48 | }); 49 | 50 | sendResult(result, reply.raw); 51 | }, 52 | }); 53 | 54 | server.listen(3000, "0.0.0.0", () => { 55 | console.log(`Server is running on http://localhost:3000/`); 56 | }); 57 | } 58 | 59 | main(); 60 | -------------------------------------------------------------------------------- /src/schema.ts: -------------------------------------------------------------------------------- 1 | import { makeExecutableSchema } from "@graphql-tools/schema"; 2 | import { GraphQLContext } from "./context"; 3 | import typeDefs from "./schema.graphql"; 4 | import { Link, User, Prisma } from "@prisma/client"; 5 | import { APP_SECRET } from "./auth"; 6 | import { hash, compare } from "bcryptjs"; 7 | import { sign } from "jsonwebtoken"; 8 | import { PubSubChannels } from "./pubsub"; 9 | 10 | const resolvers = { 11 | Query: { 12 | info: () => `This is the API of a Hackernews Clone`, 13 | feed: async ( 14 | parent: unknown, 15 | args: { 16 | filter?: string; 17 | skip?: number; 18 | take?: number; 19 | orderBy?: { 20 | description?: Prisma.SortOrder; 21 | url?: Prisma.SortOrder; 22 | createdAt?: Prisma.SortOrder; 23 | }; 24 | }, 25 | context: GraphQLContext 26 | ) => { 27 | const where = args.filter 28 | ? { 29 | OR: [ 30 | { description: { contains: args.filter } }, 31 | { url: { contains: args.filter } }, 32 | ], 33 | } 34 | : {}; 35 | 36 | const totalCount = await context.prisma.link.count({ where }); 37 | const links = await context.prisma.link.findMany({ 38 | where, 39 | skip: args.skip, 40 | take: args.take, 41 | orderBy: args.orderBy, 42 | }); 43 | 44 | return { 45 | count: totalCount, 46 | links, 47 | }; 48 | }, 49 | me: (parent: unknown, args: {}, context: GraphQLContext) => { 50 | if (context.currentUser === null) { 51 | throw new Error("Unauthenticated!"); 52 | } 53 | 54 | return context.currentUser; 55 | }, 56 | }, 57 | User: { 58 | links: (parent: User, args: {}, context: GraphQLContext) => 59 | context.prisma.user.findUnique({ where: { id: parent.id } }).links(), 60 | }, 61 | Vote: { 62 | link: (parent: User, args: {}, context: GraphQLContext) => 63 | context.prisma.vote.findUnique({ where: { id: parent.id } }).link(), 64 | user: (parent: User, args: {}, context: GraphQLContext) => 65 | context.prisma.vote.findUnique({ where: { id: parent.id } }).user(), 66 | }, 67 | Link: { 68 | id: (parent: Link) => parent.id, 69 | description: (parent: Link) => parent.description, 70 | url: (parent: Link) => parent.url, 71 | votes: (parent: Link, args: {}, context: GraphQLContext) => 72 | context.prisma.link.findUnique({ where: { id: parent.id } }).votes(), 73 | postedBy: async (parent: Link, args: {}, context: GraphQLContext) => { 74 | if (!parent.postedById) { 75 | return null; 76 | } 77 | 78 | return context.prisma.link 79 | .findUnique({ where: { id: parent.id } }) 80 | .postedBy(); 81 | }, 82 | }, 83 | Mutation: { 84 | post: async ( 85 | parent: unknown, 86 | args: { description: string; url: string }, 87 | context: GraphQLContext 88 | ) => { 89 | if (context.currentUser === null) { 90 | throw new Error("Unauthenticated!"); 91 | } 92 | 93 | const newLink = await context.prisma.link.create({ 94 | data: { 95 | url: args.url, 96 | description: args.description, 97 | postedBy: { connect: { id: context.currentUser.id } }, 98 | }, 99 | }); 100 | 101 | context.pubSub.publish("newLink", { createdLink: newLink }); 102 | 103 | return newLink; 104 | }, 105 | signup: async ( 106 | parent: unknown, 107 | args: { email: string; password: string; name: string }, 108 | context: GraphQLContext 109 | ) => { 110 | const password = await hash(args.password, 10); 111 | 112 | const user = await context.prisma.user.create({ 113 | data: { ...args, password }, 114 | }); 115 | 116 | const token = sign({ userId: user.id }, APP_SECRET); 117 | 118 | return { 119 | token, 120 | user, 121 | }; 122 | }, 123 | login: async ( 124 | parent: unknown, 125 | args: { email: string; password: string }, 126 | context: GraphQLContext 127 | ) => { 128 | const user = await context.prisma.user.findUnique({ 129 | where: { email: args.email }, 130 | }); 131 | if (!user) { 132 | throw new Error("No such user found"); 133 | } 134 | 135 | const valid = await compare(args.password, user.password); 136 | if (!valid) { 137 | throw new Error("Invalid password"); 138 | } 139 | 140 | const token = sign({ userId: user.id }, APP_SECRET); 141 | 142 | return { 143 | token, 144 | user, 145 | }; 146 | }, 147 | vote: async ( 148 | parent: unknown, 149 | args: { linkId: string }, 150 | context: GraphQLContext 151 | ) => { 152 | // 1 153 | if (!context.currentUser) { 154 | throw new Error("You must login in order to use upvote!"); 155 | } 156 | 157 | // 2 158 | const userId = context.currentUser.id; 159 | 160 | // 3 161 | const vote = await context.prisma.vote.findUnique({ 162 | where: { 163 | linkId_userId: { 164 | linkId: Number(args.linkId), 165 | userId: userId, 166 | }, 167 | }, 168 | }); 169 | 170 | if (vote !== null) { 171 | throw new Error(`Already voted for link: ${args.linkId}`); 172 | } 173 | 174 | // 4 175 | const newVote = await context.prisma.vote.create({ 176 | data: { 177 | user: { connect: { id: userId } }, 178 | link: { connect: { id: Number(args.linkId) } }, 179 | }, 180 | }); 181 | 182 | context.pubSub.publish("newVote", { createdVote: newVote }); 183 | 184 | return newVote; 185 | }, 186 | }, 187 | Subscription: { 188 | newLink: { 189 | subscribe: (parent: unknown, args: {}, context: GraphQLContext) => { 190 | return context.pubSub.asyncIterator("newLink"); 191 | }, 192 | resolve: (payload: PubSubChannels["newLink"][0]) => { 193 | return payload.createdLink; 194 | }, 195 | }, 196 | newVote: { 197 | subscribe: (parent: unknown, args: {}, context: GraphQLContext) => { 198 | return context.pubSub.asyncIterator("newVote"); 199 | }, 200 | resolve: (payload: PubSubChannels["newVote"][0]) => { 201 | return payload.createdVote; 202 | }, 203 | }, 204 | }, 205 | }; 206 | 207 | export const schema = makeExecutableSchema({ 208 | typeDefs, 209 | resolvers, 210 | }); 211 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | 26 | /* Modules */ 27 | "module": "commonjs", /* Specify what module code is generated. */ 28 | // "rootDir": "./", /* Specify the root folder within your source files. */ 29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | // "resolveJsonModule": true, /* Enable importing .json files */ 37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 38 | 39 | /* JavaScript Support */ 40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 43 | 44 | /* Emit */ 45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 50 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 51 | // "removeComments": true, /* Disable emitting comments. */ 52 | // "noEmit": true, /* Disable emitting files from a compilation. */ 53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 61 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 67 | 68 | /* Interop Constraints */ 69 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 70 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 71 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ 72 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 73 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 74 | 75 | /* Type Checking */ 76 | "strict": true, /* Enable all strict type-checking options. */ 77 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 78 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 79 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 80 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 81 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 82 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 83 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 84 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 85 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 86 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 87 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 88 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 89 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 90 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 91 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 92 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 93 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 94 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 95 | 96 | /* Completeness */ 97 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 98 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 99 | } 100 | } 101 | --------------------------------------------------------------------------------