I think there is quite a lot lacking from the above answers.
Let’s first think about what an interrupt provides. An interrupt is how we accomplish preemption in a computer system. That is, stopping program execution in arbitrary positions in their code.
All preemption in a computer system is accomplished via interrupts. Many software frameworks and operating systems have features that feel & look like preemption but without an interrupt it has not actually preempted a processor core.
There are a few different kinds of interrupts, maybe more than listed
Line Interrupts - A physical wire/pin on the CPU. Trigger types: (Edge Triggered/Level Triggered)
Messaged Interrupts - There aren’t enough pins on the CPU to support enough interrupts in modern computers. Modern CPUs such as Intel/AMD with many cores have a network inside of the CPU between cores, cache, memory & I/O. Messaged interrupts are effectively a packet in the CPU core/mesh network. It is a hw implementation.
NMI - Non-Maskable interrupt. Interrupt that cannot be ignored, most commonly used to crash/shut down a system after an uncorrectable error etc.
Interrupts controllers often supports interrupt priority.
Some interrupt controllers support interrupt nesting. (Interrupting an interrupt)
Most people talk about I/O as being the most common source of interrupts. There are a few other interrupt sources of interest.
Timers - Processor can set a hw timer & receive an interrupt when the timer expires.
MMU - memory management unit sends interrupts on TLB exceptions. Page faults etc.
Errors - Many things can generate interrupts when a correctable or uncorrectable error occurs. (DRAM, PCIe devices etc). Processor Exceptions such as overflows, zero division, segment errors, protection faults etc.
CPU Cores - Many platforms support CPU cores sending interrupts to other CPU cores. A common thing in some OS schedulers for task migrations etc.