最近的5.2.0 Neo4j JavaScript Driver版本对打字稿用户具有一些重大改进。如此之多,以至于它启发了我写一篇文章。
现在可以使用接口来定义您的Cypher查询返回的记录类型,从而在处理结果时为您带来了类型检查和类型提示的额外好处。
一个有效的例子
例如,让我们从建议数据集中进行查询。假设我们想找到电影中出现的所有演员的清单。
要找到这个,我们需要创建一个新的驱动程序实例,打开一个新的会话,然后使用executeRead()
函数发送Cypher语句并等待结果。
async function main() {
// Create a Driver Instance
const driver = neo4j.driver(
'neo4j://localhost:7687',
neo4j.auth.basic('neo4j', 'letmein!')
)
// Open a new Session
const session = driver.session()
try {
// Execute a Cypher statement in a Read Transaction
const res = await session.executeRead(tx => tx.run(`
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie {title: $title})
RETURN p, r, m
`, { title: 'Pulp Fiction' }))
const people = res.records.map(row => row.get('p'))
console.log(people)
}
finally {
// Close the Session
await session.close()
}
}
很简单,而且所有完美的开发人员都将永远不会以这种方式遇到任何问题。
另一方面,如果某人恰好在res.records.map(row => row.get('p'))
行中产生错字,或者尝试将.get()
在结果中未返回的值,则驱动程序被写成错误。
说该行更改为:
const people = res.records.map(row => row.get('something'))
由于结果中不存在something
,因此将抛出一个Neo4jError
:
Neo4jError: This record has no field with key 'something',
available key are: [p,r,m].
运行应用程序时,您最终会发现这一点,但是打字稿的全部要点是在开发过程中识别这些错误。
添加类型检查
为了防止这种类型的方案,我们现在可以使用接口来定义每个记录上可用的密钥。
在上述查询的情况下,我们有三个值:
-
p
-带有Person
标签的Node
,带有属性,包括name
和born
-
r
-Relationship
的Relationship
,带有属性,包括roles
-一系列字符串 -
m
aNode
带有Movie
的标签。
neo4j-driver
库导出了两个类型定义,即Node
和Relationship
,我们可以用来定义这些项目。
import neo4j, { Node, Relationship } from 'neo4j-driver'
这两个类都接受仿制药来定义.identity
的类型和值。
除非您在创建驱动程序时已设置disableLosslessIntegers
选项,否则身份将是从neo4j-driver
导出的Integer
类型的实例。
人值可以定义为打字稿type
。
import { Integer } from 'neo4j-driver'
interface PersonProperties {
tmdbId: string;
name: string;
born: number; // Year of birth
}
type Person = Node<Integer, PersonProperties>
或,对于更简短的示例,您可以直接在第二个通用中定义属性:
type Movie = Node<Integer, {
tmdbId: string;
title: string;
rating: number;
}>
关系几乎几乎几乎相同,但是使用Relationship
类型。
type ActedIn = Relationship<Integer, {
roles: string[];
}>
这些类型可以在接口中组合以表示结果中的每个记录:
interface PersonActedInMovie {
p: Person;
r: ActedIn;
m: Movie;
}
session.run()
和tx.run()
都接受接口,然后将类型检查添加到任何后续处理中。可以更新上面的示例将PersonActedInMovie
接口传递到tx.run()
方法调用。
// Execute a Cypher statement in a Read Transaction
const res = await session.executeRead(tx => tx.run<PersonActedInMovie>(`
MATCH (p:Person)-[r:ACTED_IN]->(m:Movie {title: $title})
RETURN p, r, m
`, { title: 'Pulp Fiction' }))
类型检查行动
由于定义了记录形状,Typescript现在将验证代码编写并提供建议。
。建议记录键
现在在调用record.get()
方法时提供建议。
暗示特性
Typescript知道people
是Person
节点的数组,在键入时可以建议在接口中定义的属性。
检查属性键
如果键在节点或关系的属性中不存在,那么Typescript将立即捡起并丢弃错误:
const names = people.map(
person => person.properties.foo
// Property 'foo' does not exist
// on type 'PersonProperties'
)
类型检查属性
typeScript现在也要注意每个属性的类型,因此,如果您尝试使用类型中未定义的值,那么Typescript将引发错误。
const names: string[] = people.map(
person => person.properties.born
)
// Type 'number[]' is not assignable to type 'string[]'.
有兴趣了解更多吗?
如果您在了解有关neo4j的更多方面很有趣,我建议您结帐Beginners Neo4j Courses on GraphAcademy。
如果您有兴趣了解更多信息,我目前正在为Neo4j GraphAcademy制作新的Neo4j & TypeScript course。
您还可以在Building Neo4j Applications with Node.js
课程中了解有关using Neo4j in a Node.js project所需的所有信息,在此过程中,您将更深入地潜入驾驶员生命周期,并用Neo4j Sandbox instance的响应代替硬编码数据。
如果您有任何评论或问题,请随时使用reach out to me on Twitter。