问题
I am fairly new to TypeScript and started to convert my existing server from ES6 to TypeScript. I am a bit lost and trying to figure out how to declare types for async functions. Here's a stub from the ES6 code:
// db.js
import { Pool } from 'pg';
const pool = new Pool({
connectionString: 'process.env.DB_CONNECTION',
});
export default {
query(text, params) {
return new Promise((resolve, reject) => {
try {
const result = pool.query(text, params);
return resolve(result);
} catch (error) {
return reject(error);
}
});
},
};
// controller for a table
const Table = {
getOne: async (id) => {
return await db.query('SELECT * FROM table WHERE id=$1', [id]);
},
}
This works fine and could be processed by consuming part in a try/catch block and it works whether the query returns a result or an error. Now how should I type these in typescript? I tried doing this:
import { Pool } from 'pg';
const pool = new Pool({
connectionString: 'process.env.DB_CONNECTION',
});
export default {
query(text: string, params: any[]) {
return new Promise((resolve, reject) => {
try {
const result = pool.query(text, params);
return resolve(result);
} catch (error) {
return reject(error);
}
});
},
};
// controller
import { QueryResult } from 'pg';
const Table = {
getOne: async (id: string) => {
return await db.query('SELECT * FROM table WHERE id=$1', [id]) as QueryResult;
},
}
Now, this compiles, but there are couple things I don't get. First, it is quite redundant to always cast these return types with 'as'. Shouldn't I be able to declare the return type somehow like this getOne: async (id: string): Promise<QueryResult> => {...}
? Then, what would happen, if the promise rejected? That isn't a QueryResult type anymore afaik. I have tried to read the documentations about node-postgres and TypeScript function type declarations, but I am getting nowhere. How I should do these? Also probably I should start learning declaration files too.
回答1:
async functions implicitly return promises
example:
// Declare async function
async function getRandomNumberAsync(max: number): Promise<number> {
return Math.floor(Math.random() * Math.floor(max));
}
// Call it (errors are handled with a try/catch)
try {
const result = await getRandomNumberAsync(100);
console.log(result);
} catch (e) {
console.error("something went wrong");
}
async/await is just syntax sugar (behind the scenes, async/await use Promises). This code is basically equivalent to the above code
function getRandomNumberAsync(max: number): Promise<number> {
return Promise.resolve(Math.floor(Math.random() * Math.floor(max)));
}
getRandomNumberAsync(100).then(result => {
console.log(result);
}).catch(e => {
console.error("something went wrong");
})
I can see that in your code, you're using return await
which is redundant. There's even an eslint rule to prevent this
Your code should look something like this
const Table = {
getOne: async (id: string): Promise<QueryResult> => {
return db.query('SELECT * FROM table WHERE id=$1', [id]);
},
}
// "getOne" should be called like this
try {
const result = await Table.getOne("YOUR_ID");
// handle result
} catch (e) {
// handle error
}
unless you want to handle query
errors inside getOne
It should look something like this
const Table = {
getOne: async (id: string): Promise<QueryResult | string> => {
try {
return await db.query("SELECT * FROM table WHERE id=$1", [id]);
} catch (e) {
return "something went wrong";
}
},
}
来源:https://stackoverflow.com/questions/60355815/how-to-type-node-postgres-async-query-functions-in-typescript